Skip to content

Commit 313147b

Browse files
authored
Add tenant role ID and name parameters for user search (#612)
1 parent 1ba7b66 commit 313147b

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

descope/management/common.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,8 @@ def sort_to_dict(sort: List[Sort]) -> list:
364364
}
365365
)
366366
return sort_list
367+
368+
def map_to_values_object(input_map: dict):
369+
if not input_map:
370+
return {}
371+
return {k: {"values": v} for k, v in input_map.items()}

descope/management/user.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
Sort,
1111
associated_tenants_to_dict,
1212
sort_to_dict,
13+
map_to_values_object,
1314
)
1415
from descope.management.user_pwd import UserPassword
1516

@@ -638,6 +639,8 @@ def search_all(
638639
from_modified_time: Optional[int] = None,
639640
to_modified_time: Optional[int] = None,
640641
user_ids: Optional[List[str]] = None,
642+
tenant_role_ids: Optional[dict] = None,
643+
tenant_role_names: Optional[dict] = None,
641644
) -> dict:
642645
"""
643646
Search all users.
@@ -662,6 +665,8 @@ def search_all(
662665
from_modified_time (int): Optional int, only include users whose last modification/update occurred on or after this time (in Unix epoch milliseconds)
663666
to_modified_time (int): Optional int, only include users whose last modification/update occurred on or before this time (in Unix epoch milliseconds)
664667
user_ids (List[str]): Optional list of user IDs to filter by
668+
tenant_role_ids (dict): Optional mapping of tenant ID to list of role IDs.
669+
tenant_role_names (dict): Optional mapping of tenant ID to list of role names.
665670
666671
Return value (dict):
667672
Return dict in the format
@@ -726,7 +731,12 @@ def search_all(
726731
body["fromModifiedTime"] = from_modified_time
727732
if to_modified_time is not None:
728733
body["toModifiedTime"] = to_modified_time
729-
734+
735+
if tenant_role_ids is not None:
736+
body["tenantRoleIds"] = map_to_values_object(tenant_role_ids)
737+
if tenant_role_names is not None:
738+
body["tenantRoleNames"] = map_to_values_object(tenant_role_names)
739+
730740
response = self._auth.do_post(
731741
MgmtV1.users_search_path,
732742
body=body,
@@ -752,6 +762,8 @@ def search_all_test_users(
752762
to_created_time: Optional[int] = None,
753763
from_modified_time: Optional[int] = None,
754764
to_modified_time: Optional[int] = None,
765+
tenant_role_ids: Optional[dict] = None,
766+
tenant_role_names: Optional[dict] = None,
755767
) -> dict:
756768
"""
757769
Search all test users.
@@ -773,6 +785,8 @@ def search_all_test_users(
773785
to_created_time (int): Optional int, only include users who were created on or before this time (in Unix epoch milliseconds)
774786
from_modified_time (int): Optional int, only include users whose last modification/update occurred on or after this time (in Unix epoch milliseconds)
775787
to_modified_time (int): Optional int, only include users whose last modification/update occurred on or before this time (in Unix epoch milliseconds)
788+
tenant_role_ids (dict): Optional mapping of tenant ID to list of role IDs.
789+
tenant_role_names (dict): Optional mapping of tenant ID to list of role names.
776790
777791
Return value (dict):
778792
Return dict in the format
@@ -834,6 +848,11 @@ def search_all_test_users(
834848
body["fromModifiedTime"] = from_modified_time
835849
if to_modified_time is not None:
836850
body["toModifiedTime"] = to_modified_time
851+
852+
if tenant_role_ids is not None:
853+
body["tenantRoleIds"] = map_to_values_object(tenant_role_ids)
854+
if tenant_role_names is not None:
855+
body["tenantRoleNames"] = map_to_values_object(tenant_role_names)
837856

838857
response = self._auth.do_post(
839858
MgmtV1.test_users_search_path,

tests/management/test_user.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,45 @@ def test_search_all(self):
10471047
timeout=DEFAULT_TIMEOUT_SECONDS,
10481048
)
10491049

1050+
# Test success flow with tenant_role_ids and tenant_role_names
1051+
with patch("requests.post") as mock_post:
1052+
network_resp = mock.Mock()
1053+
network_resp.ok = True
1054+
network_resp.json.return_value = json.loads(
1055+
"""{"users": [{"id": "u1"}, {"id": "u2"}]}"""
1056+
)
1057+
mock_post.return_value = network_resp
1058+
resp = self.client.mgmt.user.search_all(
1059+
tenant_role_ids={"tenant1": ["roleA", "roleB"]},
1060+
tenant_role_names={"tenant2": ["admin", "user"]},
1061+
)
1062+
users = resp["users"]
1063+
self.assertEqual(len(users), 2)
1064+
self.assertEqual(users[0]["id"], "u1")
1065+
self.assertEqual(users[1]["id"], "u2")
1066+
mock_post.assert_called_with(
1067+
f"{common.DEFAULT_BASE_URL}{MgmtV1.users_search_path}",
1068+
headers={
1069+
**common.default_headers,
1070+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
1071+
"x-descope-project-id": self.dummy_project_id,
1072+
},
1073+
params=None,
1074+
json={
1075+
"tenantIds": [],
1076+
"roleNames": [],
1077+
"limit": 0,
1078+
"page": 0,
1079+
"testUsersOnly": False,
1080+
"withTestUser": False,
1081+
"tenantRoleIds": {"tenant1": {"values": ["roleA", "roleB"]}},
1082+
"tenantRoleNames": {"tenant2": {"values": ["admin", "user"]}},
1083+
},
1084+
allow_redirects=False,
1085+
verify=True,
1086+
timeout=DEFAULT_TIMEOUT_SECONDS,
1087+
)
1088+
10501089
def test_search_all_test_users(self):
10511090
# Test failed flows
10521091
with patch("requests.post") as mock_post:
@@ -1254,6 +1293,45 @@ def test_search_all_test_users(self):
12541293
timeout=DEFAULT_TIMEOUT_SECONDS,
12551294
)
12561295

1296+
# Test success flow with tenant_role_ids and tenant_role_names
1297+
with patch("requests.post") as mock_post:
1298+
network_resp = mock.Mock()
1299+
network_resp.ok = True
1300+
network_resp.json.return_value = json.loads(
1301+
"""{"users": [{"id": "u1"}, {"id": "u2"}]}"""
1302+
)
1303+
mock_post.return_value = network_resp
1304+
resp = self.client.mgmt.user.search_all_test_users(
1305+
tenant_role_ids={"tenant1": ["roleA", "roleB"]},
1306+
tenant_role_names={"tenant2": ["admin", "user"]},
1307+
)
1308+
users = resp["users"]
1309+
self.assertEqual(len(users), 2)
1310+
self.assertEqual(users[0]["id"], "u1")
1311+
self.assertEqual(users[1]["id"], "u2")
1312+
mock_post.assert_called_with(
1313+
f"{common.DEFAULT_BASE_URL}{MgmtV1.test_users_search_path}",
1314+
headers={
1315+
**common.default_headers,
1316+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
1317+
"x-descope-project-id": self.dummy_project_id,
1318+
},
1319+
params=None,
1320+
json={
1321+
"tenantIds": [],
1322+
"roleNames": [],
1323+
"limit": 0,
1324+
"page": 0,
1325+
"testUsersOnly": True,
1326+
"withTestUser": True,
1327+
"tenantRoleIds": {"tenant1": {"values": ["roleA", "roleB"]}},
1328+
"tenantRoleNames": {"tenant2": {"values": ["admin", "user"]}},
1329+
},
1330+
allow_redirects=False,
1331+
verify=True,
1332+
timeout=DEFAULT_TIMEOUT_SECONDS,
1333+
)
1334+
12571335
def test_get_provider_token(self):
12581336
# Test failed flows
12591337
with patch("requests.get") as mock_post:

0 commit comments

Comments
 (0)