Skip to content

Commit 9f710fb

Browse files
committed
Load users by ID
+ tests related to descope/etc#12741
1 parent 46e4ab5 commit 9f710fb

File tree

5 files changed

+99
-1
lines changed

5 files changed

+99
-1
lines changed

.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
"mypy-type-checker.importStrategy": "fromEnvironment",
88
"isort.importStrategy": "fromEnvironment",
99
"black-formatter.importStrategy": "fromEnvironment",
10-
"workbench.colorCustomizations": { /* do not change please... */}
10+
"workbench.colorCustomizations": {
11+
"activityBar.background": "#4D1C3B",
12+
"titleBar.activeBackground": "#6B2752",
13+
"titleBar.activeForeground": "#FDF8FB"
14+
}
1115
}

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,12 @@ descope_client.mgmt.user.logout_user("<login-id>")
706706
# Logout user from all devices by user ID
707707
descope_client.mgmt.user.logout_user_by_user_id("<user-id>")
708708

709+
# Load users by their user id
710+
users_resp = descope_client.mgmt.user.load_users(user_ids=["<user-id>"])
711+
users = users_resp["users"]
712+
for user in users:
713+
# Do something
714+
709715
# Search all users, optionally according to tenant and/or role filter
710716
# results can be paginated using the limit and page parameters, as well as by time with the from_created_time, to_created_time, from_modified_time, and to_modified_time
711717
users_resp = descope_client.mgmt.user.search_all(tenant_ids=["my-tenant-id"])

descope/management/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class MgmtV1:
8787
user_logout_path = "/v1/mgmt/user/logout"
8888
user_delete_all_test_users_path = "/v1/mgmt/user/test/delete/all"
8989
user_load_path = "/v1/mgmt/user"
90+
users_load_path = "/v1/mgmt/users/load"
9091
users_search_path = "/v2/mgmt/user/search"
9192
test_users_search_path = "/v2/mgmt/user/search/test"
9293
user_get_provider_token = "/v1/mgmt/user/provider/token"

descope/management/user.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,44 @@ def logout_user_by_user_id(
653653
body={"userId": user_id},
654654
)
655655

656+
def load_users(
657+
self,
658+
user_ids: List[str] = None,
659+
include_invalid_users: Optional[bool] = None,
660+
) -> dict:
661+
"""
662+
Search all users.
663+
664+
Args:
665+
user_ids (List[str]): Optional list of user IDs to filter by
666+
include_invalid_users (bool): Optional flag to include invalid users in the response
667+
668+
Return value (dict):
669+
Return dict in the format
670+
{"users": []}
671+
"users" contains a list of all of the found users and their information
672+
673+
Raise:
674+
AuthException: raised if search operation fails
675+
"""
676+
if user_ids is None or len(user_ids) == 0:
677+
raise AuthException(
678+
400, ERROR_TYPE_INVALID_ARGUMENT, "At list one user id needs to be supplied"
679+
)
680+
681+
body: dict[str, Union[List[str], bool]] = {
682+
"userIds": user_ids,
683+
}
684+
685+
if include_invalid_users is not None:
686+
body["includeInvalidUsers"] = include_invalid_users
687+
688+
response = self._http.post(
689+
MgmtV1.users_load_path,
690+
body=body,
691+
)
692+
return response.json()
693+
656694
def search_all(
657695
self,
658696
tenant_ids: Optional[List[str]] = None,

tests/management/test_user.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,55 @@ def test_load_by_user_id(self):
10131013
timeout=DEFAULT_TIMEOUT_SECONDS,
10141014
)
10151015

1016+
def test_load_users(self):
1017+
# Test failed flows
1018+
with patch("requests.post") as mock_post:
1019+
mock_post.return_value.ok = False
1020+
self.assertRaises(
1021+
AuthException,
1022+
self.client.mgmt.user.load_users,
1023+
[""],
1024+
)
1025+
1026+
with patch("requests.post") as mock_post:
1027+
mock_post.return_value.ok = True
1028+
self.assertRaises(
1029+
AuthException, self.client.mgmt.user.load_users, None, False
1030+
)
1031+
1032+
# Test success flow
1033+
with patch("requests.post") as mock_post:
1034+
network_resp = mock.Mock()
1035+
network_resp.ok = True
1036+
network_resp.json.return_value = json.loads(
1037+
"""{"users": [{"id": "u1"}, {"id": "u2"}]}"""
1038+
)
1039+
mock_post.return_value = network_resp
1040+
resp = self.client.mgmt.user.load_users(
1041+
["uid"],
1042+
include_invalid_users=True,
1043+
)
1044+
users = resp["users"]
1045+
self.assertEqual(len(users), 2)
1046+
self.assertEqual(users[0]["id"], "u1")
1047+
self.assertEqual(users[1]["id"], "u2")
1048+
mock_post.assert_called_with(
1049+
f"{common.DEFAULT_BASE_URL}{MgmtV1.users_load_path}",
1050+
headers={
1051+
**common.default_headers,
1052+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
1053+
"x-descope-project-id": self.dummy_project_id,
1054+
},
1055+
params=None,
1056+
json={
1057+
"userIds": ["uid"],
1058+
"includeInvalidUsers": True,
1059+
},
1060+
allow_redirects=False,
1061+
verify=True,
1062+
timeout=DEFAULT_TIMEOUT_SECONDS,
1063+
)
1064+
10161065
def test_search_all(self):
10171066
# Test failed flows
10181067
with patch("requests.post") as mock_post:

0 commit comments

Comments
 (0)