Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions cms/djangoapps/contentstore/tests/test_course_listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,9 @@ def test_get_course_keys_from_scopes_with_platform_scope(self):
"is_enabled",
side_effect=self._mock_authz_toggle(enabled_keys),
):
course_keys = _get_course_keys_from_scopes([PlatformCourseOverviewGlobData(external_key="course-v1:*")])
course_keys = _get_course_keys_from_scopes([
PlatformCourseOverviewGlobData(external_key=PlatformCourseOverviewGlobData.build_external_key())
])

assert course_keys == set(authz_keys) | set(legacy_keys)

Expand All @@ -993,7 +995,9 @@ def test_get_course_keys_from_scopes_with_platform_scope_global_flag_enabled(sel
"is_enabled",
side_effect=self._mock_authz_toggle(enabled_keys, global_enabled=True),
):
course_keys = _get_course_keys_from_scopes([PlatformCourseOverviewGlobData(external_key="course-v1:*")])
course_keys = _get_course_keys_from_scopes([
PlatformCourseOverviewGlobData(external_key=PlatformCourseOverviewGlobData.build_external_key())
])

assert course_keys == set(CourseOverview.get_all_courses().values_list("id", flat=True))

Expand All @@ -1012,8 +1016,8 @@ def test_get_course_keys_from_scopes_platform_scope_short_circuits(self):
):
course_keys = _get_course_keys_from_scopes(
[
OrgCourseOverviewGlobData(external_key="course-v1:Org1+*"),
PlatformCourseOverviewGlobData(external_key="course-v1:*"),
OrgCourseOverviewGlobData(external_key=OrgCourseOverviewGlobData.build_external_key("Org1")),
PlatformCourseOverviewGlobData(external_key=PlatformCourseOverviewGlobData.build_external_key()),
]
)

Expand Down
5 changes: 5 additions & 0 deletions common/djangoapps/student/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,11 @@ def _authz_get_orgs_for_user(self, user) -> list[str]:
user_external_key=user.username,
role_external_key=role,
)
# A platform-wide grant (course-v1:*, lib:*) covers every org, not just the ones
# with a concrete assignment. Platform-glob scopes have no .org attribute at all
# (unlike org-glob/course/library scopes, where it's a real field that can be None).
if any(assignment.scope.IS_PLATFORM_GLOB for assignment in assignments):
return [org["short_name"] for org in get_organizations()]
Comment thread
efortish marked this conversation as resolved.
orgs = {assignment.scope.org for assignment in assignments if assignment.scope.org is not None}
return list(orgs)

Expand Down
56 changes: 56 additions & 0 deletions common/djangoapps/student/tests/test_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from openedx_authz.constants.roles import COURSE_ADMIN, COURSE_STAFF
from openedx_authz.engine.enforcer import AuthzEnforcer
from organizations.api import add_organization
from organizations.tests.factories import OrganizationFactory

from common.djangoapps.student.admin import CourseAccessRoleHistoryAdmin
from common.djangoapps.student.models import CourseAccessRoleHistory, User
Expand Down Expand Up @@ -316,6 +317,61 @@ def test_get_orgs_for_user_authz(self):
result = role.get_orgs_for_user(self.student)
self.assertCountEqual(result, [self.course_key.org, other_org]) # noqa: PT009

@override_waffle_flag(AUTHZ_COURSE_AUTHORING_FLAG, active=True)
def test_get_orgs_for_user_authz_platform_glob(self):
"""
A platform-wide glob assignment (course-v1:*) has no `.org` attribute, unlike
course/org-glob scopes. get_orgs_for_user must special-case it and return every
registered org instead of crashing with an AttributeError.
"""
role = CourseStaffRole(self.course_key)

for org in self.orgs:
OrganizationFactory(short_name=org, name=org)

assign_role_to_user_in_scope(
self.student.username,
COURSE_STAFF.external_key,
PlatformCourseOverviewGlobData.build_external_key(),
)
AuthzEnforcer.get_enforcer().load_policy()
Comment thread
efortish marked this conversation as resolved.

result = role.get_orgs_for_user(self.student)
assert sorted(result) == sorted(self.orgs)
assert role.has_org_for_user(self.student)
assert role.has_org_for_user(self.student, org=self.orgs[0])

@override_waffle_flag(AUTHZ_COURSE_AUTHORING_FLAG, active=True)
def test_get_orgs_for_user_authz_platform_glob_vs_org_scoped(self):
"""
Side-by-side check that the platform-glob branch (return every registered org)
and the regular branch (return only the orgs with a concrete assignment) produce
the same list[str] shape, over the same pool of registered orgs: an org-scoped
grant returns a subset, a platform-wide grant returns all of them.
"""
role = CourseStaffRole(self.course_key)
third_org = "Universal"
all_orgs = [*self.orgs, third_org]

for org in all_orgs:
OrganizationFactory(short_name=org, name=org)

subset_user = UserFactory()
assign_role_to_user_in_scope(
subset_user.username,
COURSE_STAFF.external_key,
OrgCourseOverviewGlobData.build_external_key(self.orgs[0]),
)
assign_role_to_user_in_scope(
self.student.username,
COURSE_STAFF.external_key,
PlatformCourseOverviewGlobData.build_external_key(),
)
AuthzEnforcer.get_enforcer().load_policy()

assert sorted(role.get_orgs_for_user(subset_user)) == [self.orgs[0]]
assert sorted(role.get_orgs_for_user(self.student)) == sorted(all_orgs)

def test_get_authz_compat_course_access_roles_for_user(self):
"""
Test that get_authz_compat_course_access_roles_for_user doesn't crash when the user
Expand Down
Loading