Skip to content

Commit 2c9d4eb

Browse files
committed
feat: add api function to retrieve role assignments for users filtered by role
1 parent 164865f commit 2c9d4eb

3 files changed

Lines changed: 62 additions & 1 deletion

File tree

openedx_authz/api/roles.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"unassign_role_from_subject_in_scope",
3838
"batch_unassign_role_from_subjects_in_scope",
3939
"get_subject_role_assignments_in_scope",
40+
"get_subject_role_assignments_for_role",
4041
"get_subject_role_assignments_for_role_in_scope",
4142
"get_all_subject_role_assignments_in_scope",
4243
"get_subject_role_assignments",
@@ -323,6 +324,23 @@ def get_subject_role_assignments_in_scope(subject: SubjectData, scope: ScopeData
323324
return role_assignments
324325

325326

327+
def get_subject_role_assignments_for_role(subject: SubjectData, role: RoleData) -> list[RoleAssignmentData]:
328+
"""Get role assignments for a subject filtered by a specific role across all scopes.
329+
330+
Args:
331+
subject: The SubjectData object representing the subject.
332+
role: The RoleData object representing the role to filter by.
333+
334+
Returns:
335+
list[RoleAssignmentData]: A list of assignments where the subject has the specified role.
336+
"""
337+
return [
338+
assignment
339+
for assignment in get_subject_role_assignments(subject)
340+
if any(assigned_role.namespaced_key == role.namespaced_key for assigned_role in assignment.roles)
341+
]
342+
343+
326344
def get_subject_role_assignments_for_role_in_scope(role: RoleData, scope: ScopeData) -> list[RoleAssignmentData]:
327345
"""Get the subjects assigned to a specific role in a specific scope.
328346

openedx_authz/api/users.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@
99
(e.g., 'user^john_doe').
1010
"""
1111

12-
from openedx_authz.api.data import ActionData, PermissionData, RoleAssignmentData, RoleData, ScopeData, UserData
12+
from openedx_authz.api.data import (
13+
ActionData,
14+
PermissionData,
15+
RoleAssignmentData,
16+
RoleData,
17+
ScopeData,
18+
UserData,
19+
)
1320
from openedx_authz.api.permissions import is_subject_allowed
1421
from openedx_authz.api.roles import (
1522
assign_role_to_subject_in_scope,
@@ -18,6 +25,7 @@
1825
get_all_subject_role_assignments_in_scope,
1926
get_scopes_for_subject_and_permission,
2027
get_subject_role_assignments,
28+
get_subject_role_assignments_for_role,
2129
get_subject_role_assignments_for_role_in_scope,
2230
get_subject_role_assignments_in_scope,
2331
get_subjects_for_role_in_scope,
@@ -38,6 +46,7 @@
3846
"get_scopes_for_user_and_permission",
3947
"get_users_for_role_in_scope",
4048
"unassign_all_roles_from_user",
49+
"get_user_role_assignments_for_role",
4150
]
4251

4352

@@ -121,6 +130,22 @@ def get_user_role_assignments(user_external_key: str) -> list[RoleAssignmentData
121130
return get_subject_role_assignments(UserData(external_key=user_external_key))
122131

123132

133+
def get_user_role_assignments_for_role(user_external_key: str, role_external_key: str) -> list[RoleAssignmentData]:
134+
"""Get role assignments for a user filtered by a specific role across all scopes.
135+
136+
Args:
137+
user_external_key (str): ID of the user (e.g., 'john_doe').
138+
role_external_key (str): Name of the role (e.g., 'instructor').
139+
140+
Returns:
141+
list[RoleAssignmentData]: A list of role assignments for the given user and role.
142+
"""
143+
return get_subject_role_assignments_for_role(
144+
UserData(external_key=user_external_key),
145+
RoleData(external_key=role_external_key),
146+
)
147+
148+
124149
def get_user_role_assignments_in_scope(user_external_key: str, scope_external_key: str) -> list[RoleAssignmentData]:
125150
"""Get the roles assigned to a user in a specific scope.
126151

openedx_authz/tests/api/test_roles.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
get_role_definitions_in_scope,
3232
get_scopes_for_subject_and_permission,
3333
get_subject_role_assignments,
34+
get_subject_role_assignments_for_role,
3435
get_subject_role_assignments_for_role_in_scope,
3536
get_subject_role_assignments_in_scope,
3637
get_subjects_for_role_in_scope,
@@ -603,6 +604,23 @@ def test_get_all_role_assignments_scopes(self, subject_name, expected_roles):
603604
found = any(expected_role in assignment.roles for assignment in role_assignments)
604605
self.assertTrue(found, f"Expected role {expected_role} not found in assignments")
605606

607+
@ddt_data(
608+
("liam", roles.LIBRARY_AUTHOR.external_key, 3),
609+
("eve", roles.LIBRARY_ADMIN.external_key, 1),
610+
("eve", roles.LIBRARY_AUTHOR.external_key, 1),
611+
("eve", roles.LIBRARY_USER.external_key, 1),
612+
("alice", roles.LIBRARY_AUTHOR.external_key, 0),
613+
("non_existent_user", roles.LIBRARY_ADMIN.external_key, 0),
614+
)
615+
@unpack
616+
def test_get_subject_role_assignments_for_role(self, subject_name, role_name, expected_count):
617+
"""Test retrieving role assignments for a subject filtered by role across all scopes."""
618+
role_assignments = get_subject_role_assignments_for_role(
619+
SubjectData(external_key=subject_name),
620+
RoleData(external_key=role_name),
621+
)
622+
self.assertEqual(len(role_assignments), expected_count)
623+
606624
@ddt_data(
607625
(roles.LIBRARY_ADMIN.external_key, "lib:Org1:math_101", 1),
608626
(roles.LIBRARY_AUTHOR.external_key, "lib:Org1:history_201", 1),

0 commit comments

Comments
 (0)