willisapi-client 1.6__tar.gz → 1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {willisapi_client-1.6 → willisapi_client-1.7}/PKG-INFO +1 -1
- {willisapi_client-1.6 → willisapi_client-1.7}/tests/test_auth.py +0 -58
- {willisapi_client-1.6 → willisapi_client-1.7}/tests/test_download.py +9 -2
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/__init__.py +1 -3
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/__version__.py +1 -1
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/api.py +1 -1
- willisapi_client-1.7/willisapi_client/services/auth/__init__.py +6 -0
- willisapi_client-1.7/willisapi_client/services/auth/auth_utils.py +52 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/download/download_handler.py +2 -1
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/download/download_utils.py +46 -20
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/willisapi_client.py +1 -10
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client.egg-info/PKG-INFO +1 -1
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client.egg-info/SOURCES.txt +0 -3
- willisapi_client-1.6/tests/test_user_permissions.py +0 -72
- willisapi_client-1.6/willisapi_client/services/auth/__init__.py +0 -8
- willisapi_client-1.6/willisapi_client/services/auth/account_manager.py +0 -49
- willisapi_client-1.6/willisapi_client/services/auth/auth_utils.py +0 -143
- willisapi_client-1.6/willisapi_client/services/auth/permissions_manager.py +0 -44
- {willisapi_client-1.6 → willisapi_client-1.7}/LICENSE +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/MANIFEST.in +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/README.md +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/RELEASE.md +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/requirements.txt +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/setup.cfg +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/setup.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/tests/test_csv_validation.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/tests/test_upload.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/logging_setup.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/__init__.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/auth/login_manager.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/download/__init__.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/exceptions.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/__init__.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/csv_validation.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/language_choices.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/multipart_upload_handler.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/upload_utils.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/utils.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/timer.py +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client.egg-info/dependency_links.txt +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client.egg-info/not-zip-safe +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client.egg-info/requires.txt +0 -0
- {willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from willisapi_client.services.auth.login_manager import login
|
|
2
2
|
|
|
3
|
-
from willisapi_client.services.auth.account_manager import account_create
|
|
4
3
|
from unittest.mock import patch
|
|
5
4
|
from datetime import timedelta, datetime
|
|
6
5
|
|
|
@@ -68,60 +67,3 @@ class TestLoginFunction:
|
|
|
68
67
|
key, expire_in = login(self.username, self.password)
|
|
69
68
|
assert key == None
|
|
70
69
|
assert expire_in == None
|
|
71
|
-
|
|
72
|
-
@patch("willisapi_client.services.auth.account_manager.AuthUtils.account_create")
|
|
73
|
-
def test_create_account_success(self, mocked_create_account):
|
|
74
|
-
mocked_create_account.return_value = {
|
|
75
|
-
"status_code": 200,
|
|
76
|
-
"message": "Account Created Successfully",
|
|
77
|
-
}
|
|
78
|
-
result = account_create(
|
|
79
|
-
self.id_token,
|
|
80
|
-
self.account,
|
|
81
|
-
)
|
|
82
|
-
assert result == "Account Created Successfully"
|
|
83
|
-
|
|
84
|
-
@patch("willisapi_client.services.auth.account_manager.AuthUtils.account_create")
|
|
85
|
-
def test_create_account_failed(self, mocked_create_account):
|
|
86
|
-
mocked_create_account.return_value = {
|
|
87
|
-
"status_code": 400,
|
|
88
|
-
"message": "Validation Error",
|
|
89
|
-
}
|
|
90
|
-
result = account_create(
|
|
91
|
-
self.id_token,
|
|
92
|
-
self.account,
|
|
93
|
-
)
|
|
94
|
-
assert result == "Validation Error"
|
|
95
|
-
|
|
96
|
-
@patch("willisapi_client.services.auth.account_manager.AuthUtils.account_create")
|
|
97
|
-
def test_create_account_failed_for_non_admin_user(self, mocked_create_account):
|
|
98
|
-
mocked_create_account.return_value = {
|
|
99
|
-
"status_code": 401,
|
|
100
|
-
"message": "Not an Admin",
|
|
101
|
-
}
|
|
102
|
-
result = account_create(
|
|
103
|
-
self.id_token,
|
|
104
|
-
self.account,
|
|
105
|
-
)
|
|
106
|
-
assert result == "Not an Admin"
|
|
107
|
-
|
|
108
|
-
@patch("willisapi_client.services.auth.account_manager.AuthUtils.account_create")
|
|
109
|
-
def test_create_account_failed_unexpected(self, mocked_create_account):
|
|
110
|
-
mocked_create_account.return_value = {
|
|
111
|
-
"status_code": 500,
|
|
112
|
-
"message": None,
|
|
113
|
-
}
|
|
114
|
-
result = account_create(
|
|
115
|
-
self.id_token,
|
|
116
|
-
self.account,
|
|
117
|
-
)
|
|
118
|
-
assert result == None
|
|
119
|
-
|
|
120
|
-
@patch("willisapi_client.services.auth.account_manager.AuthUtils.account_create")
|
|
121
|
-
def test_create_account_failed_no_response_from_server(self, mocked_create_account):
|
|
122
|
-
mocked_create_account.return_value = {}
|
|
123
|
-
result = account_create(
|
|
124
|
-
self.id_token,
|
|
125
|
-
self.account,
|
|
126
|
-
)
|
|
127
|
-
assert result == None
|
|
@@ -38,16 +38,23 @@ class TestDownloadFunction:
|
|
|
38
38
|
def test_download_no_items_from_api(self, mocked_data):
|
|
39
39
|
mocked_data.return_value = {
|
|
40
40
|
"status_code": 200,
|
|
41
|
-
"
|
|
41
|
+
"presigned_url": None,
|
|
42
42
|
}
|
|
43
43
|
data = download(self.key, self.project_name)
|
|
44
44
|
assert data.empty == True
|
|
45
45
|
|
|
46
46
|
@patch("willisapi_client.services.download.download_utils.DownloadUtils.request")
|
|
47
|
-
|
|
47
|
+
@patch(
|
|
48
|
+
"willisapi_client.services.download.download_utils.DownloadUtils.get_data_from_presigned_url"
|
|
49
|
+
)
|
|
50
|
+
def test_download_success(self, mocked_data, mocked_response):
|
|
48
51
|
with open("tests/test.json") as json_file:
|
|
49
52
|
data = json.load(json_file)
|
|
50
53
|
mocked_data.return_value = data
|
|
54
|
+
mocked_response.return_value = {
|
|
55
|
+
"status_code": 200,
|
|
56
|
+
"presigned_url": "https://google.com",
|
|
57
|
+
}
|
|
51
58
|
data = download(self.key, self.project_name)
|
|
52
59
|
assert data.empty == False
|
|
53
60
|
assert data.filename.tolist()[0] == "test_video.mp4"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Version details for willisapi_client
|
|
2
2
|
"""
|
|
3
3
|
__client__ = "willisapi_client"
|
|
4
|
-
__latestVersion__ = "1.
|
|
4
|
+
__latestVersion__ = "1.7"
|
|
5
5
|
__url__ = "https://github.com/bklynhlth/willsiapi_client"
|
|
6
6
|
__short_description__ = "A Python client for willisapi"
|
|
7
7
|
__content_type__ = "text/markdown"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# website: https://www.brooklyn.health
|
|
2
2
|
|
|
3
3
|
# import the required packages
|
|
4
|
-
from willisapi_client.services.auth import login
|
|
4
|
+
from willisapi_client.services.auth import login
|
|
5
5
|
from willisapi_client.services.upload import upload
|
|
6
6
|
from willisapi_client.services.download import download
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import time
|
|
3
|
+
import json
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
from willisapi_client.services.exceptions import (
|
|
7
|
+
UnableToLoginClientError,
|
|
8
|
+
UnableToCreateAccountError,
|
|
9
|
+
UnableToUpdatePermissionsClientError,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AuthUtils:
|
|
14
|
+
@staticmethod
|
|
15
|
+
def login(url, data, headers, try_number):
|
|
16
|
+
"""
|
|
17
|
+
------------------------------------------------------------------------------------------------------
|
|
18
|
+
Class: AuthUtils
|
|
19
|
+
|
|
20
|
+
Function: login
|
|
21
|
+
|
|
22
|
+
Description: This function makes a POST API call to the brooklyn.health API server to authenticate a user.
|
|
23
|
+
|
|
24
|
+
Parameters:
|
|
25
|
+
----------
|
|
26
|
+
url: The URL of the API endpoint.
|
|
27
|
+
data: The data to be sent in the request body.
|
|
28
|
+
headers: The headers to be sent in the request.
|
|
29
|
+
try_number: The number of times the function has been tried.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
----------
|
|
33
|
+
json: The JSON response from the API server.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
----------
|
|
37
|
+
UnableToLoginClientError: If the function fails to login after 3 tries.
|
|
38
|
+
------------------------------------------------------------------------------------------------------
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
response = requests.post(url, json=data, headers=headers)
|
|
42
|
+
res_json = response.json()
|
|
43
|
+
except (
|
|
44
|
+
requests.exceptions.ConnectionError,
|
|
45
|
+
json.decoder.JSONDecodeError,
|
|
46
|
+
) as ex:
|
|
47
|
+
if try_number == 3:
|
|
48
|
+
raise UnableToLoginClientError
|
|
49
|
+
time.sleep(random.random() * 2)
|
|
50
|
+
return AuthUtils.login(url, data, headers, try_number=try_number + 1)
|
|
51
|
+
else:
|
|
52
|
+
return res_json
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/download/download_handler.py
RENAMED
|
@@ -43,7 +43,8 @@ def download(key: str, project_name: str, **kwargs):
|
|
|
43
43
|
logger.error("No access to project/data for download.")
|
|
44
44
|
if response["status_code"] == HTTPStatus.OK:
|
|
45
45
|
logger.info(f'{datetime.now().strftime("%H:%M:%S")}: Download Complete')
|
|
46
|
-
|
|
46
|
+
data = DownloadUtils.get_data_from_presigned_url(response["presigned_url"])
|
|
47
|
+
response_df, err = DownloadUtils.generate_response_df(data)
|
|
47
48
|
if not err:
|
|
48
49
|
return response_df
|
|
49
50
|
return empty_response_df
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/download/download_utils.py
RENAMED
|
@@ -4,6 +4,8 @@ import time
|
|
|
4
4
|
import random
|
|
5
5
|
import pandas as pd
|
|
6
6
|
from typing import Tuple
|
|
7
|
+
from http import HTTPStatus
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
vocal_acoustic_summary = "vocal_acoustics_summary"
|
|
9
11
|
speech_characteristics_summary = "speech_characteristics_summary"
|
|
@@ -64,8 +66,8 @@ class DownloadUtils:
|
|
|
64
66
|
------------------------------------------------------------------------------------------------------
|
|
65
67
|
"""
|
|
66
68
|
return (
|
|
67
|
-
response["
|
|
68
|
-
len(response["
|
|
69
|
+
response["project"]["project_name"],
|
|
70
|
+
len(response["project"]["participant"]),
|
|
69
71
|
)
|
|
70
72
|
|
|
71
73
|
def _get_pt_id_ext_and_num_records(response, pt):
|
|
@@ -88,8 +90,8 @@ class DownloadUtils:
|
|
|
88
90
|
------------------------------------------------------------------------------------------------------
|
|
89
91
|
"""
|
|
90
92
|
return (
|
|
91
|
-
response["
|
|
92
|
-
len(response["
|
|
93
|
+
response["project"]["participant"][pt]["participant_Id"],
|
|
94
|
+
len(response["project"]["participant"][pt]["results"]),
|
|
93
95
|
)
|
|
94
96
|
|
|
95
97
|
def _get_filename_and_timestamp(response, pt, rec):
|
|
@@ -113,12 +115,8 @@ class DownloadUtils:
|
|
|
113
115
|
------------------------------------------------------------------------------------------------------
|
|
114
116
|
"""
|
|
115
117
|
return (
|
|
116
|
-
response["
|
|
117
|
-
|
|
118
|
-
],
|
|
119
|
-
response["items"]["project"]["participant"][pt]["results"][rec][
|
|
120
|
-
"timestamp"
|
|
121
|
-
],
|
|
118
|
+
response["project"]["participant"][pt]["results"][rec]["file_name"],
|
|
119
|
+
response["project"]["participant"][pt]["results"][rec]["timestamp"],
|
|
122
120
|
)
|
|
123
121
|
|
|
124
122
|
def _get_defined_columns():
|
|
@@ -158,7 +156,7 @@ class DownloadUtils:
|
|
|
158
156
|
df: A pandas dataframe of specific workflow tag
|
|
159
157
|
------------------------------------------------------------------------------------------------------
|
|
160
158
|
"""
|
|
161
|
-
measures_dict = response["
|
|
159
|
+
measures_dict = response["project"]["participant"][pt]["results"][rec][
|
|
162
160
|
"measures"
|
|
163
161
|
]
|
|
164
162
|
if (
|
|
@@ -174,7 +172,35 @@ class DownloadUtils:
|
|
|
174
172
|
return pd.read_json(json.dumps(measures_dict[workflow_tag][0]))
|
|
175
173
|
return pd.DataFrame()
|
|
176
174
|
|
|
177
|
-
def
|
|
175
|
+
def get_data_from_presigned_url(url: str):
|
|
176
|
+
"""
|
|
177
|
+
------------------------------------------------------------------------------------------------------
|
|
178
|
+
Class: DownloadUtils
|
|
179
|
+
|
|
180
|
+
Function: get_data_from_presigned_url
|
|
181
|
+
|
|
182
|
+
Description: This function downloads the json data using S3 preisgned URL
|
|
183
|
+
|
|
184
|
+
Parameters:
|
|
185
|
+
----------
|
|
186
|
+
response: S3 Presigned URL
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
----------
|
|
190
|
+
(data, error): Generates response data and error message
|
|
191
|
+
------------------------------------------------------------------------------------------------------
|
|
192
|
+
"""
|
|
193
|
+
response = {}
|
|
194
|
+
try:
|
|
195
|
+
data = requests.get(url)
|
|
196
|
+
if data.status_code == HTTPStatus.OK:
|
|
197
|
+
response = data.json()
|
|
198
|
+
except Exception:
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
return response
|
|
202
|
+
|
|
203
|
+
def generate_response_df(data) -> Tuple[pd.DataFrame, str]:
|
|
178
204
|
"""
|
|
179
205
|
------------------------------------------------------------------------------------------------------
|
|
180
206
|
Class: DownloadUtils
|
|
@@ -185,7 +211,7 @@ class DownloadUtils:
|
|
|
185
211
|
|
|
186
212
|
Parameters:
|
|
187
213
|
----------
|
|
188
|
-
|
|
214
|
+
data: The JSON data from the API server.
|
|
189
215
|
|
|
190
216
|
Returns:
|
|
191
217
|
----------
|
|
@@ -194,20 +220,20 @@ class DownloadUtils:
|
|
|
194
220
|
"""
|
|
195
221
|
response_df = pd.DataFrame()
|
|
196
222
|
try:
|
|
197
|
-
if not
|
|
223
|
+
if not data:
|
|
198
224
|
return response_df, "No Data Found"
|
|
199
225
|
(project_name, num_pts) = DownloadUtils._get_project_name_and_pts_count(
|
|
200
|
-
|
|
226
|
+
data
|
|
201
227
|
)
|
|
202
228
|
for pt in range(0, num_pts):
|
|
203
229
|
(pt_id_ext, num_records) = DownloadUtils._get_pt_id_ext_and_num_records(
|
|
204
|
-
|
|
230
|
+
data, pt
|
|
205
231
|
)
|
|
206
232
|
for rec in range(0, num_records):
|
|
207
233
|
(
|
|
208
234
|
filename,
|
|
209
235
|
time_collected,
|
|
210
|
-
) = DownloadUtils._get_filename_and_timestamp(
|
|
236
|
+
) = DownloadUtils._get_filename_and_timestamp(data, pt, rec)
|
|
211
237
|
main_df = pd.DataFrame(
|
|
212
238
|
[[project_name, pt_id_ext, filename, time_collected]],
|
|
213
239
|
columns=DownloadUtils._get_defined_columns(),
|
|
@@ -215,16 +241,16 @@ class DownloadUtils:
|
|
|
215
241
|
|
|
216
242
|
vocal_acoustics_summary_df = (
|
|
217
243
|
DownloadUtils._get_summary_df_from_json(
|
|
218
|
-
|
|
244
|
+
data, pt, rec, vocal_acoustic_summary
|
|
219
245
|
)
|
|
220
246
|
)
|
|
221
247
|
speech_characteristics_summary_df = (
|
|
222
248
|
DownloadUtils._get_summary_df_from_json(
|
|
223
|
-
|
|
249
|
+
data, pt, rec, speech_characteristics_summary
|
|
224
250
|
)
|
|
225
251
|
)
|
|
226
252
|
rater_qa_summary_df = DownloadUtils._get_summary_df_from_json(
|
|
227
|
-
|
|
253
|
+
data, pt, rec, rater_qa_summary
|
|
228
254
|
)
|
|
229
255
|
df = pd.concat(
|
|
230
256
|
[
|
|
@@ -15,7 +15,6 @@ class WillisapiClient:
|
|
|
15
15
|
self.client_version = get_client_version()
|
|
16
16
|
self.api_version = math.floor(self.client_version)
|
|
17
17
|
self.api_uri = "api.brooklyn.health"
|
|
18
|
-
self.app_url = f"app.brooklyn.health/api/v{self.api_version}/"
|
|
19
18
|
self.env = kwargs["env"] if "env" in kwargs else None
|
|
20
19
|
|
|
21
20
|
def get_base_url(self):
|
|
@@ -33,15 +32,7 @@ class WillisapiClient:
|
|
|
33
32
|
return self.get_base_url() + "upload"
|
|
34
33
|
|
|
35
34
|
def get_download_url(self):
|
|
36
|
-
|
|
37
|
-
return f"https://{self.env}-{self.app_url}download"
|
|
38
|
-
return f"https://{self.app_url}download"
|
|
39
|
-
|
|
40
|
-
def get_account_create_url(self):
|
|
41
|
-
return self.get_base_url() + "account-create"
|
|
42
|
-
|
|
43
|
-
def get_user_permissions_url(self):
|
|
44
|
-
return self.get_base_url() + "user-permissions"
|
|
35
|
+
return self.get_base_url() + "download"
|
|
45
36
|
|
|
46
37
|
def get_headers(self):
|
|
47
38
|
return {"Content-Type": "application/json", "Accept": "application/json"}
|
|
@@ -9,7 +9,6 @@ tests/test_auth.py
|
|
|
9
9
|
tests/test_csv_validation.py
|
|
10
10
|
tests/test_download.py
|
|
11
11
|
tests/test_upload.py
|
|
12
|
-
tests/test_user_permissions.py
|
|
13
12
|
willisapi_client/__init__.py
|
|
14
13
|
willisapi_client/__version__.py
|
|
15
14
|
willisapi_client/logging_setup.py
|
|
@@ -25,10 +24,8 @@ willisapi_client/services/__init__.py
|
|
|
25
24
|
willisapi_client/services/api.py
|
|
26
25
|
willisapi_client/services/exceptions.py
|
|
27
26
|
willisapi_client/services/auth/__init__.py
|
|
28
|
-
willisapi_client/services/auth/account_manager.py
|
|
29
27
|
willisapi_client/services/auth/auth_utils.py
|
|
30
28
|
willisapi_client/services/auth/login_manager.py
|
|
31
|
-
willisapi_client/services/auth/permissions_manager.py
|
|
32
29
|
willisapi_client/services/download/__init__.py
|
|
33
30
|
willisapi_client/services/download/download_handler.py
|
|
34
31
|
willisapi_client/services/download/download_utils.py
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
from unittest.mock import patch
|
|
2
|
-
from willisapi_client.services.auth.permissions_manager import user_permissions
|
|
3
|
-
|
|
4
|
-
import sys
|
|
5
|
-
import logging
|
|
6
|
-
|
|
7
|
-
logger = logging.getLogger()
|
|
8
|
-
logger.level = logging.INFO
|
|
9
|
-
stream_handler = logging.StreamHandler(sys.stdout)
|
|
10
|
-
logger.addHandler(stream_handler)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class TestUserPermissions:
|
|
14
|
-
def setup_method(self):
|
|
15
|
-
self.username = "dummy"
|
|
16
|
-
self.password = "password"
|
|
17
|
-
self.id_token = "dummy_token"
|
|
18
|
-
self.user_email = "dummy@gmail.com"
|
|
19
|
-
self.client_name = "dummy_group"
|
|
20
|
-
self.expires_in = 100
|
|
21
|
-
self.failed_message = "Something went wrong"
|
|
22
|
-
self.invalid_role = "Invalid role"
|
|
23
|
-
|
|
24
|
-
@patch("willisapi_client.services.auth.login_manager.AuthUtils.user_permissions")
|
|
25
|
-
def test_user_permissions_failed(self, mocked_user_permissions):
|
|
26
|
-
mocked_user_permissions.return_value = {
|
|
27
|
-
"status_code": 500,
|
|
28
|
-
"message": self.failed_message,
|
|
29
|
-
}
|
|
30
|
-
message = user_permissions(
|
|
31
|
-
self.id_token, self.user_email, self.client_name, "rw"
|
|
32
|
-
)
|
|
33
|
-
assert message == self.failed_message
|
|
34
|
-
|
|
35
|
-
def test_user_permissions_invalidrole(self):
|
|
36
|
-
message = user_permissions(
|
|
37
|
-
self.id_token, self.user_email, self.client_name, "rww"
|
|
38
|
-
)
|
|
39
|
-
assert message == self.invalid_role
|
|
40
|
-
|
|
41
|
-
@patch("willisapi_client.services.auth.login_manager.AuthUtils.user_permissions")
|
|
42
|
-
def test_user_permissions_unauthoristed(self, mocked_user_permissions):
|
|
43
|
-
mocked_user_permissions.return_value = {
|
|
44
|
-
"status_code": 401,
|
|
45
|
-
"message": "not an admin",
|
|
46
|
-
}
|
|
47
|
-
message = user_permissions(
|
|
48
|
-
self.id_token, self.user_email, self.client_name, "rw"
|
|
49
|
-
)
|
|
50
|
-
assert message == "not an admin"
|
|
51
|
-
|
|
52
|
-
@patch("willisapi_client.services.auth.login_manager.AuthUtils.user_permissions")
|
|
53
|
-
def test_user_permissions_success(self, mocked_user_permissions):
|
|
54
|
-
mocked_user_permissions.return_value = {
|
|
55
|
-
"status_code": 200,
|
|
56
|
-
"message": "success",
|
|
57
|
-
}
|
|
58
|
-
message = user_permissions(
|
|
59
|
-
self.id_token, self.user_email, self.client_name, "rw"
|
|
60
|
-
)
|
|
61
|
-
assert message == "success"
|
|
62
|
-
|
|
63
|
-
@patch("willisapi_client.services.auth.login_manager.AuthUtils.user_permissions")
|
|
64
|
-
def test_user_permissions_invalid_group(self, mocked_user_permissions):
|
|
65
|
-
mocked_user_permissions.return_value = {
|
|
66
|
-
"status_code": 404,
|
|
67
|
-
"message": "Account not found",
|
|
68
|
-
}
|
|
69
|
-
message = user_permissions(
|
|
70
|
-
self.id_token, self.user_email, self.client_name, "rw"
|
|
71
|
-
)
|
|
72
|
-
assert message == "Account not found"
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# website: https://www.brooklyn.health
|
|
2
|
-
from willisapi_client.services.auth.login_manager import (
|
|
3
|
-
login,
|
|
4
|
-
)
|
|
5
|
-
from willisapi_client.services.auth.permissions_manager import user_permissions
|
|
6
|
-
from willisapi_client.services.auth.account_manager import account_create
|
|
7
|
-
|
|
8
|
-
__all__ = ["login", "user_permissions", "account_create"]
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# website: https://www.brooklyn.health
|
|
2
|
-
from http import HTTPStatus
|
|
3
|
-
|
|
4
|
-
from willisapi_client.willisapi_client import WillisapiClient
|
|
5
|
-
from willisapi_client.services.auth.auth_utils import AuthUtils
|
|
6
|
-
from willisapi_client.logging_setup import logger as logger
|
|
7
|
-
|
|
8
|
-
from datetime import datetime
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def account_create(
|
|
12
|
-
key: str,
|
|
13
|
-
account: str,
|
|
14
|
-
**kwargs,
|
|
15
|
-
) -> str:
|
|
16
|
-
"""
|
|
17
|
-
---------------------------------------------------------------------------------------------------
|
|
18
|
-
Function: account_create
|
|
19
|
-
|
|
20
|
-
Description: This function to creates account in RDS and AWS Cognito using willis account create API
|
|
21
|
-
|
|
22
|
-
Parameters:
|
|
23
|
-
----------
|
|
24
|
-
key: Admin access token
|
|
25
|
-
account: Client Name
|
|
26
|
-
|
|
27
|
-
Returns:
|
|
28
|
-
----------
|
|
29
|
-
None
|
|
30
|
-
---------------------------------------------------------------------------------------------------
|
|
31
|
-
"""
|
|
32
|
-
wc = WillisapiClient(env=kwargs.get("env"))
|
|
33
|
-
url = wc.get_account_create_url()
|
|
34
|
-
headers = wc.get_headers()
|
|
35
|
-
headers["Authorization"] = key
|
|
36
|
-
data = dict(
|
|
37
|
-
account=account.lower(),
|
|
38
|
-
)
|
|
39
|
-
logger.info(f'{datetime.now().strftime("%H:%M:%S")}: Creating account')
|
|
40
|
-
response = AuthUtils.account_create(url, data, headers, try_number=1)
|
|
41
|
-
if response and "status_code" in response:
|
|
42
|
-
if response["status_code"] == HTTPStatus.OK:
|
|
43
|
-
logger.info(response["message"])
|
|
44
|
-
else:
|
|
45
|
-
logger.error(response["message"])
|
|
46
|
-
return response["message"]
|
|
47
|
-
else:
|
|
48
|
-
logger.error(f"Failed")
|
|
49
|
-
return None
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
import time
|
|
3
|
-
import json
|
|
4
|
-
import random
|
|
5
|
-
|
|
6
|
-
from willisapi_client.services.exceptions import (
|
|
7
|
-
UnableToLoginClientError,
|
|
8
|
-
UnableToCreateAccountError,
|
|
9
|
-
UnableToUpdatePermissionsClientError,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class AuthUtils:
|
|
14
|
-
@staticmethod
|
|
15
|
-
def login(url, data, headers, try_number):
|
|
16
|
-
"""
|
|
17
|
-
------------------------------------------------------------------------------------------------------
|
|
18
|
-
Class: AuthUtils
|
|
19
|
-
|
|
20
|
-
Function: login
|
|
21
|
-
|
|
22
|
-
Description: This function makes a POST API call to the brooklyn.health API server to authenticate a user.
|
|
23
|
-
|
|
24
|
-
Parameters:
|
|
25
|
-
----------
|
|
26
|
-
url: The URL of the API endpoint.
|
|
27
|
-
data: The data to be sent in the request body.
|
|
28
|
-
headers: The headers to be sent in the request.
|
|
29
|
-
try_number: The number of times the function has been tried.
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
----------
|
|
33
|
-
json: The JSON response from the API server.
|
|
34
|
-
|
|
35
|
-
Raises:
|
|
36
|
-
----------
|
|
37
|
-
UnableToLoginClientError: If the function fails to login after 3 tries.
|
|
38
|
-
------------------------------------------------------------------------------------------------------
|
|
39
|
-
"""
|
|
40
|
-
try:
|
|
41
|
-
response = requests.post(url, json=data, headers=headers)
|
|
42
|
-
res_json = response.json()
|
|
43
|
-
except (
|
|
44
|
-
requests.exceptions.ConnectionError,
|
|
45
|
-
json.decoder.JSONDecodeError,
|
|
46
|
-
) as ex:
|
|
47
|
-
if try_number == 3:
|
|
48
|
-
raise UnableToLoginClientError
|
|
49
|
-
time.sleep(random.random() * 2)
|
|
50
|
-
return AuthUtils.login(url, data, headers, try_number=try_number + 1)
|
|
51
|
-
else:
|
|
52
|
-
return res_json
|
|
53
|
-
|
|
54
|
-
@staticmethod
|
|
55
|
-
def account_create(url, data, headers, try_number):
|
|
56
|
-
"""
|
|
57
|
-
------------------------------------------------------------------------------------------------------
|
|
58
|
-
Class: AuthUtils
|
|
59
|
-
|
|
60
|
-
Function: account_create
|
|
61
|
-
|
|
62
|
-
Description: This is an internal account_create function which makes a POST API call to the brooklyn.health API server.
|
|
63
|
-
|
|
64
|
-
Parameters:
|
|
65
|
-
----------
|
|
66
|
-
url: The URL of the API endpoint.
|
|
67
|
-
data: The data to be sent in the request body.
|
|
68
|
-
headers: The headers to be sent in the request.
|
|
69
|
-
try_number: The number of times the function has been tried.
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
----------
|
|
73
|
-
json: The JSON response from the API server.
|
|
74
|
-
|
|
75
|
-
Raises:
|
|
76
|
-
----------
|
|
77
|
-
UnableToCreateAccountError: If the function fails to signup after 3 tries.
|
|
78
|
-
------------------------------------------------------------------------------------------------------
|
|
79
|
-
"""
|
|
80
|
-
try:
|
|
81
|
-
response = requests.post(url, json=data, headers=headers)
|
|
82
|
-
res_json = response.json()
|
|
83
|
-
except (
|
|
84
|
-
requests.exceptions.ConnectionError,
|
|
85
|
-
json.decoder.JSONDecodeError,
|
|
86
|
-
) as ex:
|
|
87
|
-
if try_number == 3:
|
|
88
|
-
raise UnableToCreateAccountError
|
|
89
|
-
time.sleep(random.random() * 2)
|
|
90
|
-
return AuthUtils.account_create(url, data, headers, try_number)
|
|
91
|
-
else:
|
|
92
|
-
return res_json
|
|
93
|
-
|
|
94
|
-
@staticmethod
|
|
95
|
-
def user_permissions(url, data, headers, try_number):
|
|
96
|
-
"""
|
|
97
|
-
------------------------------------------------------------------------------------------------------
|
|
98
|
-
Class: AuthUtils
|
|
99
|
-
|
|
100
|
-
Function: user_permissions
|
|
101
|
-
|
|
102
|
-
Description: This function makes a POST API call to the brooklyn.health API server to update user permissions.
|
|
103
|
-
|
|
104
|
-
Parameters:
|
|
105
|
-
----------
|
|
106
|
-
url: The URL of the API endpoint.
|
|
107
|
-
data: The data to be sent in the request body.
|
|
108
|
-
headers: The headers to be sent in the request.
|
|
109
|
-
try_number: The number of times the function has been tried.
|
|
110
|
-
|
|
111
|
-
Returns:
|
|
112
|
-
----------
|
|
113
|
-
json: The JSON response from the API server.
|
|
114
|
-
|
|
115
|
-
Raises:
|
|
116
|
-
----------
|
|
117
|
-
UnableToLoginClientError: If the function fails to login after 3 tries.
|
|
118
|
-
------------------------------------------------------------------------------------------------------
|
|
119
|
-
"""
|
|
120
|
-
try:
|
|
121
|
-
response = requests.post(url, json=data, headers=headers)
|
|
122
|
-
res_json = response.json()
|
|
123
|
-
except (
|
|
124
|
-
requests.exceptions.ConnectionError,
|
|
125
|
-
json.decoder.JSONDecodeError,
|
|
126
|
-
) as ex:
|
|
127
|
-
if try_number == 3:
|
|
128
|
-
raise UnableToUpdatePermissionsClientError
|
|
129
|
-
time.sleep(random.random() * 2)
|
|
130
|
-
return AuthUtils.user_permissions(
|
|
131
|
-
url, data, headers, try_number=try_number + 1
|
|
132
|
-
)
|
|
133
|
-
else:
|
|
134
|
-
return res_json
|
|
135
|
-
|
|
136
|
-
@staticmethod
|
|
137
|
-
def validate_role(role: str):
|
|
138
|
-
READ = "r"
|
|
139
|
-
READ_WRITE = "rw"
|
|
140
|
-
FULL_ACCESS = "*"
|
|
141
|
-
if role in [READ, READ_WRITE, FULL_ACCESS]:
|
|
142
|
-
return True
|
|
143
|
-
return False
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
from http import HTTPStatus
|
|
2
|
-
|
|
3
|
-
from willisapi_client.willisapi_client import WillisapiClient
|
|
4
|
-
from willisapi_client.services.auth.auth_utils import AuthUtils
|
|
5
|
-
from willisapi_client.logging_setup import logger as logger
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def user_permissions(
|
|
9
|
-
key: str, user_email: str, account: str, role: str, **kwargs
|
|
10
|
-
) -> str:
|
|
11
|
-
"""
|
|
12
|
-
---------------------------------------------------------------------------------------------------
|
|
13
|
-
Function: user_permissions
|
|
14
|
-
|
|
15
|
-
Description: This function is responsible for making a call to the /user_permissions API for access control
|
|
16
|
-
|
|
17
|
-
Parameters:
|
|
18
|
-
----------
|
|
19
|
-
key: string representation of id_token generate after login
|
|
20
|
-
user_email: string representation of user's email
|
|
21
|
-
account: string representation of account/client name
|
|
22
|
-
role: r/rw/*
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
----------
|
|
26
|
-
None
|
|
27
|
-
|
|
28
|
-
---------------------------------------------------------------------------------------------------
|
|
29
|
-
"""
|
|
30
|
-
wc = WillisapiClient(env=kwargs.get("env"))
|
|
31
|
-
url = wc.get_user_permissions_url()
|
|
32
|
-
headers = wc.get_headers()
|
|
33
|
-
headers["Authorization"] = key
|
|
34
|
-
data = dict(user_email=user_email, account=account, role=role)
|
|
35
|
-
is_role_valid = AuthUtils.validate_role(role)
|
|
36
|
-
if is_role_valid:
|
|
37
|
-
response = AuthUtils.user_permissions(url, data, headers, try_number=1)
|
|
38
|
-
message = response["message"]
|
|
39
|
-
logger.info(message)
|
|
40
|
-
else:
|
|
41
|
-
message = "Invalid role"
|
|
42
|
-
logger.info(message)
|
|
43
|
-
|
|
44
|
-
return message
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/auth/login_manager.py
RENAMED
|
File without changes
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/download/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/csv_validation.py
RENAMED
|
File without changes
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/language_choices.py
RENAMED
|
File without changes
|
|
File without changes
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client/services/upload/upload_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{willisapi_client-1.6 → willisapi_client-1.7}/willisapi_client.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|