Skip to content

Commit c152f07

Browse files
authored
Load users by ID (#698)
+ tests related to descope/etc#12741
1 parent 46e4ab5 commit c152f07

File tree

5 files changed

+97
-1
lines changed

5 files changed

+97
-1
lines changed

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: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,46 @@ def logout_user_by_user_id(
653653
body={"userId": user_id},
654654
)
655655

656+
def load_users(
657+
self,
658+
user_ids: List[str],
659+
include_invalid_users: Optional[bool] = None,
660+
) -> dict:
661+
"""
662+
Load users by their user IDs.
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,
679+
ERROR_TYPE_INVALID_ARGUMENT,
680+
"At least one user id needs to be supplied",
681+
)
682+
683+
body: dict[str, Union[List[str], bool]] = {
684+
"userIds": user_ids,
685+
}
686+
687+
if include_invalid_users is not None:
688+
body["includeInvalidUsers"] = include_invalid_users
689+
690+
response = self._http.post(
691+
MgmtV1.users_load_path,
692+
body=body,
693+
)
694+
return response.json()
695+
656696
def search_all(
657697
self,
658698
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:

tests/test_descope_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ def test_base_url_none(self):
10761076
public_key=self.public_key_dict,
10771077
)
10781078

1079-
expected_base_url = common.DEFAULT_BASE_URL
1079+
expected_base_url = common.DEFAULT_BASE_URL
10801080
self.assertEqual(client._auth.http_client.base_url, expected_base_url)
10811081
self.assertEqual(client._mgmt._http.base_url, expected_base_url)
10821082

0 commit comments

Comments
 (0)