Skip to content

Commit 23c86b8

Browse files
authored
feat: add pagination support to get realm roles (#659)
1 parent 5fbefac commit 23c86b8

2 files changed

Lines changed: 71 additions & 14 deletions

File tree

src/keycloak/keycloak_admin.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,7 +2910,9 @@ def get_realm_users_profile(self) -> dict:
29102910
)
29112911
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])
29122912

2913-
def get_realm_roles(self, brief_representation: bool = True, search_text: str = "") -> list:
2913+
def get_realm_roles(
2914+
self, brief_representation: bool = True, search_text: str = "", query: dict | None = None
2915+
) -> list:
29142916
"""
29152917
Get all roles for the realm or client.
29162918
@@ -2921,20 +2923,23 @@ def get_realm_roles(self, brief_representation: bool = True, search_text: str =
29212923
:type brief_representation: bool
29222924
:param search_text: optional search text to limit the returned result.
29232925
:type search_text: str
2926+
:param query: Query parameters (optional)
2927+
:type query: dict
29242928
:return: Keycloak server response (RoleRepresentation)
29252929
:rtype: list
29262930
"""
2931+
query = query or {}
29272932
params_path = {"realm-name": self.connection.realm_name}
29282933
params = {"briefRepresentation": brief_representation}
2934+
url = urls_patterns.URL_ADMIN_REALM_ROLES.format(**params_path)
29292935

29302936
if search_text is not None and search_text.strip() != "":
29312937
params["search"] = search_text
29322938

2933-
data_raw = self.connection.raw_get(
2934-
urls_patterns.URL_ADMIN_REALM_ROLES.format(**params_path),
2935-
**params,
2936-
)
2937-
return raise_error_from_response(data_raw, KeycloakGetError)
2939+
if "first" in query and "max" in query:
2940+
return self.__fetch_paginated(url, query)
2941+
2942+
return self.__fetch_all(url, params)
29382943

29392944
def get_realm_role_groups(
29402945
self,
@@ -8176,9 +8181,7 @@ async def a_get_realm_users_profile(self) -> dict:
81768181
return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[HTTP_OK])
81778182

81788183
async def a_get_realm_roles(
8179-
self,
8180-
brief_representation: bool = True,
8181-
search_text: str = "",
8184+
self, brief_representation: bool = True, search_text: str = "", query: dict | None = None
81828185
) -> list:
81838186
"""
81848187
Get all roles for the realm or client asynchronously.
@@ -8190,20 +8193,23 @@ async def a_get_realm_roles(
81908193
:type brief_representation: bool
81918194
:param search_text: optional search text to limit the returned result.
81928195
:type search_text: str
8196+
:param query: Query parameters (optional)
8197+
:type query: dict
81938198
:return: Keycloak server response (RoleRepresentation)
81948199
:rtype: list
81958200
"""
8201+
query = query or {}
81968202
params_path = {"realm-name": self.connection.realm_name}
81978203
params = {"briefRepresentation": brief_representation}
8204+
url = urls_patterns.URL_ADMIN_REALM_ROLES.format(**params_path)
81988205

81998206
if search_text is not None and search_text.strip() != "":
82008207
params["search"] = search_text
82018208

8202-
data_raw = await self.connection.a_raw_get(
8203-
urls_patterns.URL_ADMIN_REALM_ROLES.format(**params_path),
8204-
**params,
8205-
)
8206-
return raise_error_from_response(data_raw, KeycloakGetError)
8209+
if "first" in query and "max" in query:
8210+
return await self.a___fetch_paginated(url, query)
8211+
8212+
return await self.a___fetch_all(url, params)
82078213

82088214
async def a_get_realm_role_groups(
82098215
self,

tests/test_keycloak_admin.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,31 @@ def test_realm_roles(admin: KeycloakAdmin, realm: str) -> None:
16621662
assert err.match(COULD_NOT_FIND_ROLE_REGEX)
16631663

16641664

1665+
def test_realm_roles_pagination(admin: KeycloakAdmin, realm: str) -> None:
1666+
"""
1667+
Test realm roles pagination.
1668+
1669+
:param admin: Keycloak admin
1670+
:type admin: KeycloakAdmin
1671+
:param realm: Keycloak realm
1672+
:type realm: str
1673+
"""
1674+
admin.change_current_realm(realm)
1675+
1676+
for ind in range(admin.PAGE_SIZE + 50 - 3):
1677+
role_name = f"role_{ind:03}"
1678+
admin.create_realm_role(payload={"name": role_name})
1679+
1680+
roles = admin.get_realm_roles()
1681+
assert len(roles) == admin.PAGE_SIZE + 50, len(roles)
1682+
1683+
roles = admin.get_realm_roles(query={"first": 100, "max": 20})
1684+
assert len(roles) == 20, len(roles)
1685+
1686+
roles = admin.get_realm_roles(query={"first": 120, "max": 50})
1687+
assert len(roles) == 30, len(roles)
1688+
1689+
16651690
@pytest.mark.parametrize(
16661691
("testcase", "arg_brief_repr", "includes_attributes"),
16671692
[
@@ -5194,6 +5219,32 @@ async def test_a_realm_roles(admin: KeycloakAdmin, realm: str) -> None:
51945219
assert err.match(COULD_NOT_FIND_ROLE_REGEX)
51955220

51965221

5222+
@pytest.mark.asyncio
5223+
async def test_a_realm_roles_pagination(admin: KeycloakAdmin, realm: str) -> None:
5224+
"""
5225+
Test realm roles pagination.
5226+
5227+
:param admin: Keycloak admin
5228+
:type admin: KeycloakAdmin
5229+
:param realm: Keycloak realm
5230+
:type realm: str
5231+
"""
5232+
admin.change_current_realm(realm)
5233+
5234+
for ind in range(admin.PAGE_SIZE + 50 - 3):
5235+
role_name = f"role_{ind:03}"
5236+
admin.create_realm_role(payload={"name": role_name})
5237+
5238+
roles = await admin.a_get_realm_roles()
5239+
assert len(roles) == admin.PAGE_SIZE + 50, len(roles)
5240+
5241+
roles = await admin.a_get_realm_roles(query={"first": 100, "max": 20})
5242+
assert len(roles) == 20, len(roles)
5243+
5244+
roles = await admin.a_get_realm_roles(query={"first": 120, "max": 50})
5245+
assert len(roles) == 30, len(roles)
5246+
5247+
51975248
@pytest.mark.asyncio
51985249
@pytest.mark.parametrize(
51995250
("testcase", "arg_brief_repr", "includes_attributes"),

0 commit comments

Comments
 (0)