Skip to content

Commit e713ae0

Browse files
committed
squash!: generalize course and library scope queryset preparation
1 parent 1709561 commit e713ae0

1 file changed

Lines changed: 55 additions & 24 deletions

File tree

openedx_authz/rest_api/v1/views.py

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,44 @@ def _get_libraries_queryset(
768768
ScopesQuerySetFields.SCOPE_TYPE,
769769
)
770770

771+
@staticmethod
772+
def _get_allowed_scope_queryset(
773+
*,
774+
username: str,
775+
scope_cls: type,
776+
glob_cls: type,
777+
get_permission: callable,
778+
queryset_builder: callable,
779+
extract_ids: callable,
780+
search: str = "",
781+
org: str = "",
782+
) -> QuerySet:
783+
"""Resolve allowed scopes from Casbin and return a filtered queryset.
784+
785+
This helper encapsulates the shared pattern of:
786+
1. Fetching allowed scopes for a user and permission.
787+
2. Partitioning them into specific IDs vs org-level globs.
788+
3. Delegating to the appropriate queryset builder.
789+
790+
Args:
791+
username: The username to check permissions for.
792+
scope_cls: The concrete scope data class (e.g., CourseOverviewData).
793+
glob_cls: The org-level glob class (e.g., OrgCourseOverviewGlobData).
794+
get_permission: Callable that returns the permission for a scope class.
795+
queryset_builder: Callable that builds the filtered queryset (e.g., _get_courses_queryset).
796+
extract_ids: Callable that extracts specific IDs from non-glob scopes.
797+
search: Optional search term to filter by display name.
798+
org: Optional org short_name to filter by.
799+
800+
Returns:
801+
QuerySet: The filtered queryset projected to the unified scope shape.
802+
"""
803+
allowed_scopes = get_scopes_for_user_and_permission(username, get_permission(scope_cls).identifier)
804+
specific_scopes = [s for s in allowed_scopes if not isinstance(s, glob_cls)]
805+
allowed_ids = extract_ids(specific_scopes)
806+
allowed_orgs = {s.org for s in allowed_scopes if isinstance(s, glob_cls)}
807+
return queryset_builder(allowed_ids, allowed_orgs, search=search, org=org)
808+
771809
def _build_queryset(self, courses_qs: QuerySet | None, libraries_qs: QuerySet | None) -> QuerySet:
772810
"""Union the provided querysets and sort deterministically.
773811
@@ -811,38 +849,31 @@ def get_queryset(self) -> QuerySet:
811849
def get_permission(scope_cls):
812850
return scope_cls.get_admin_manage_permission() if management_only else scope_cls.get_admin_view_permission()
813851

814-
# Resolve allowed scopes from Casbin in a single call per scope type.
852+
# Resolve allowed scopes from Casbin and build filtered querysets.
815853
courses_qs = None
816854
if scope_type != ScopesTypeField.LIBRARY:
817-
allowed_course_scopes = get_scopes_for_user_and_permission(
818-
user.username, get_permission(CourseOverviewData).identifier
819-
)
820-
allowed_course_ids = {
821-
s.external_key for s in allowed_course_scopes if not isinstance(s, OrgCourseOverviewGlobData)
822-
}
823-
allowed_course_orgs = {s.org for s in allowed_course_scopes if isinstance(s, OrgCourseOverviewGlobData)}
824-
courses_qs = self._get_courses_queryset(
825-
allowed_course_ids,
826-
allowed_course_orgs,
855+
courses_qs = self._get_allowed_scope_queryset(
856+
username=user.username,
857+
scope_cls=CourseOverviewData,
858+
glob_cls=OrgCourseOverviewGlobData,
859+
get_permission=get_permission,
860+
queryset_builder=self._get_courses_queryset,
861+
extract_ids=lambda scopes: {s.external_key for s in scopes},
827862
search=search,
828863
org=org,
829864
)
830865

831866
libraries_qs = None
832867
if scope_type != ScopesTypeField.COURSE:
833-
allowed_library_scopes = get_scopes_for_user_and_permission(
834-
user.username, get_permission(ContentLibraryData).identifier
835-
)
836-
allowed_library_pairs = {
837-
# Library external keys have the format lib:<org>:<slug>
838-
(s.external_key.split(":")[1], s.external_key.split(":")[2])
839-
for s in allowed_library_scopes
840-
if not isinstance(s, OrgContentLibraryGlobData)
841-
}
842-
allowed_library_orgs = {s.org for s in allowed_library_scopes if isinstance(s, OrgContentLibraryGlobData)}
843-
libraries_qs = self._get_libraries_queryset(
844-
allowed_library_pairs,
845-
allowed_library_orgs,
868+
libraries_qs = self._get_allowed_scope_queryset(
869+
username=user.username,
870+
scope_cls=ContentLibraryData,
871+
glob_cls=OrgContentLibraryGlobData,
872+
get_permission=get_permission,
873+
queryset_builder=self._get_libraries_queryset,
874+
extract_ids=lambda scopes: {
875+
(s.external_key.split(":")[1], s.external_key.split(":")[2]) for s in scopes
876+
},
846877
search=search,
847878
org=org,
848879
)

0 commit comments

Comments
 (0)