Skip to content
Open
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
6 changes: 6 additions & 0 deletions common/djangoapps/student/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from openedx_authz.api import users as authz_api
from openedx_authz.api.data import CourseOverviewData, OrgCourseOverviewGlobData, RoleAssignmentData
from openedx_authz.constants import roles as authz_roles
from organizations.api import get_organizations

from common.djangoapps.student.models import CourseAccessRole
from common.djangoapps.student.signals.signals import emit_course_access_role_added, emit_course_access_role_removed
Expand Down Expand Up @@ -632,6 +633,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()]
orgs = {assignment.scope.org for assignment in assignments if assignment.scope.org is not None}
return list(orgs)

Expand Down
29 changes: 29 additions & 0 deletions common/djangoapps/student/tests/test_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
ContentLibraryData,
CourseOverviewData,
OrgCourseOverviewGlobData,
PlatformCourseOverviewGlobData,
RoleAssignmentData,
RoleData,
ScopeData,
UserData,
)
from openedx_authz.constants.roles import COURSE_ADMIN, COURSE_STAFF
from openedx_authz.engine.enforcer import AuthzEnforcer
from organizations.api import add_organization

from common.djangoapps.student.admin import CourseAccessRoleHistoryAdmin
from common.djangoapps.student.models import CourseAccessRoleHistory, User
Expand Down Expand Up @@ -313,6 +315,33 @@ 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:
add_organization({"name": org, "short_name": org, "description": ""})

staff_authz_role = RoleData(external_key=COURSE_STAFF)
assignments = [
RoleAssignmentData(
subject=UserData(external_key=self.student.username),
roles=[staff_authz_role],
scope=PlatformCourseOverviewGlobData(external_key="course-v1:*"),
),
]

with patch("openedx_authz.api.users.get_user_role_assignments_filtered", return_value=assignments):
result = role.get_orgs_for_user(self.student)
self.assertCountEqual(result, self.orgs) # noqa: PT009
assert role.has_org_for_user(self.student)
assert role.has_org_for_user(self.student, org=self.orgs[0])

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