Skip to content

Commit 90d8cf0

Browse files
committed
squash!: Generalize user assignments filters
1 parent 0fb615a commit 90d8cf0

4 files changed

Lines changed: 60 additions & 29 deletions

File tree

openedx_authz/api/data.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,3 +1183,9 @@ def __repr__(self):
11831183
"""Developer friendly string representation of the role assignment."""
11841184
role_keys = ", ".join(role.namespaced_key for role in self.roles)
11851185
return f"{self.subject.namespaced_key} => [{role_keys}] @ {self.scope.namespaced_key}"
1186+
1187+
1188+
@define
1189+
class UserAssignments:
1190+
user: "User"
1191+
assignments: list[RoleAssignmentData]

openedx_authz/rest_api/data.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,10 @@ class RoleOperationError(BaseEnum):
5050
USER_DOES_NOT_HAVE_ROLE = "user_does_not_have_role"
5151
ROLE_ASSIGNMENT_ERROR = "role_assignment_error"
5252
ROLE_REMOVAL_ERROR = "role_removal_error"
53+
54+
55+
class UserAssignmentsFilter(BaseEnum):
56+
"""Enum for the filters that can be applied over UserAssignments."""
57+
58+
SCOPES = "scopes"
59+
ORGS = "orgs"

openedx_authz/rest_api/utils.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Utility functions for the Open edX AuthZ REST API."""
22

33
import logging
4-
from dataclasses import dataclass
54

65
from django.contrib.auth import get_user_model
76

@@ -13,10 +12,11 @@
1312
OrgCourseOverviewGlobData,
1413
RoleAssignmentData,
1514
ScopeData,
15+
UserAssignments,
1616
)
1717
from openedx_authz.api.users import is_user_allowed
1818
from openedx_authz.constants.permissions import COURSES_VIEW_COURSE, VIEW_LIBRARY
19-
from openedx_authz.rest_api.data import SearchField, SortField, SortOrder
19+
from openedx_authz.rest_api.data import SearchField, SortField, SortOrder, UserAssignmentsFilter
2020

2121
logger = logging.getLogger(__name__)
2222

@@ -131,12 +131,6 @@ def filter_users(users: list[dict], search: str | None, roles: list[str] | None)
131131
return filtered_users
132132

133133

134-
@dataclass
135-
class UserAssignments:
136-
user: "User"
137-
assignments: list[RoleAssignmentData]
138-
139-
140134
def get_user_assignment_map(role_assignments: list[RoleAssignmentData]) -> list[UserAssignments]:
141135
"""
142136
Group role assignments by user
@@ -175,3 +169,33 @@ def filter_allowed_assignments(user: "User", assignments: list[RoleAssignmentDat
175169
allowed_assignments.append(assignment)
176170

177171
return allowed_assignments
172+
173+
174+
def filter_user_assignments(
175+
users_with_assignments: list[UserAssignments],
176+
by: UserAssignmentsFilter,
177+
values: list[str],
178+
) -> list[UserAssignments]:
179+
"""
180+
Filter user assignments by orgs or scopes.
181+
"""
182+
if not values:
183+
return users_with_assignments
184+
185+
def _get_value_to_filter(assignment: RoleAssignmentData) -> str:
186+
if by == UserAssignmentsFilter.SCOPES:
187+
return assignment.scope.external_key
188+
elif by == UserAssignmentsFilter.ORGS:
189+
return assignment.scope.org
190+
else:
191+
raise ValueError(f"Invalid filter: '{by}'. Must be one of {UserAssignmentsFilter.values()}")
192+
193+
filtered_users: list[UserAssignments] = []
194+
for uwa in users_with_assignments:
195+
if any(_get_value_to_filter(a) in values for a in uwa.assignments):
196+
# Also filter assignments to reflect the correct number of assignments
197+
filtered_assignments = [a for a in uwa.assignments if _get_value_to_filter(a) in values]
198+
filtered_users.append(UserAssignments(user=uwa.user, assignments=filtered_assignments))
199+
users_with_assignments = filtered_users
200+
201+
return filtered_users

openedx_authz/rest_api/v1/views.py

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
from openedx_authz import api
1818
from openedx_authz.constants import permissions
19-
from openedx_authz.rest_api.data import RoleOperationError, RoleOperationStatus, SortField
19+
from openedx_authz.rest_api.data import RoleOperationError, RoleOperationStatus, SortField, UserAssignmentsFilter
2020
from openedx_authz.rest_api.decorators import authz_permissions, view_auth_classes
2121
from openedx_authz.rest_api.utils import (
22-
UserAssignments,
2322
filter_allowed_assignments,
23+
filter_user_assignments,
2424
filter_users,
2525
get_generic_scope,
2626
get_user_assignment_map,
@@ -500,25 +500,19 @@ def get(self, request: HttpRequest) -> Response:
500500
order = query_params.get("order")
501501
sort_by = query_params.get("sort_by", SortField.USERNAME)
502502

503-
if scopes:
504-
# Filter by scopes
505-
filtered_users: list[UserAssignments] = []
506-
for uwa in users_with_assignments:
507-
if any(a.scope.external_key in scopes for a in uwa.assignments):
508-
# Also filter assignments to reflect the correct number of assignments
509-
filtered_assignments = [a for a in uwa.assignments if a.scope.external_key in scopes]
510-
filtered_users.append(UserAssignments(user=uwa.user, assignments=filtered_assignments))
511-
users_with_assignments = filtered_users
512-
513-
if orgs:
514-
# Filter by orgs
515-
filtered_users: list[UserAssignments] = []
516-
for uwa in users_with_assignments:
517-
if any(a.scope.org in orgs for a in uwa.assignments):
518-
# Also filter assignments to reflect the correct number of assignments
519-
filtered_assignments = [a for a in uwa.assignments if a.scope.org in orgs]
520-
filtered_users.append(UserAssignments(user=uwa.user, assignments=filtered_assignments))
521-
users_with_assignments = filtered_users
503+
# Filter by scopes
504+
users_with_assignments = filter_user_assignments(
505+
users_with_assignments=users_with_assignments,
506+
by=UserAssignmentsFilter.SCOPES,
507+
values=scopes,
508+
)
509+
510+
# Filter by orgs
511+
users_with_assignments = filter_user_assignments(
512+
users_with_assignments=users_with_assignments,
513+
by=UserAssignmentsFilter.ORGS,
514+
values=orgs,
515+
)
522516

523517
team_members = TeamMemberSerializer(users_with_assignments, many=True)
524518
# Search

0 commit comments

Comments
 (0)