diff --git a/common/djangoapps/student/roles.py b/common/djangoapps/student/roles.py index 6a26e0f4db70..c8c0b5f09441 100644 --- a/common/djangoapps/student/roles.py +++ b/common/djangoapps/student/roles.py @@ -533,9 +533,13 @@ def _authz_get_orgs_for_user(self, user) -> list[str]: Returns a list of org short names for the user with given role. AuthZ compatibility layer """ - # TODO: This will be implemented on Milestone 1 - # of the Authz for Course Authoring project - return [] + role = get_authz_role_from_legacy_role(self._role_name) + assignments = authz_api.get_user_role_assignments_filtered( + user_external_key=user.username, + role_external_key=role, + ) + orgs = {assignment.scope.org for assignment in assignments if assignment.scope.org is not None} + return list(orgs) def _legacy_get_orgs_for_user(self, user) -> list[str]: """ diff --git a/common/djangoapps/student/tests/test_roles.py b/common/djangoapps/student/tests/test_roles.py index c95d0c5af8a3..c1e861ba6a4c 100644 --- a/common/djangoapps/student/tests/test_roles.py +++ b/common/djangoapps/student/tests/test_roles.py @@ -2,7 +2,6 @@ Tests of student.roles """ - from unittest.mock import patch import ddt @@ -11,7 +10,8 @@ from edx_toggles.toggles.testutils import override_waffle_flag from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryLocator -from openedx_authz.api.data import ContentLibraryData, RoleAssignmentData, RoleData, UserData +from openedx_authz.api.data import ContentLibraryData, CourseOverviewData, RoleAssignmentData, RoleData, UserData +from openedx_authz.constants.roles import COURSE_ADMIN, COURSE_STAFF from openedx_authz.engine.enforcer import AuthzEnforcer from common.djangoapps.student.admin import CourseAccessRoleHistoryAdmin @@ -239,9 +239,51 @@ def test_get_orgs_for_user(self): role_second_org.add_users(self.student) assert len(role.get_orgs_for_user(self.student)) == 2 + @override_waffle_flag(AUTHZ_COURSE_AUTHORING_FLAG, active=True) + def test_get_orgs_for_user_authz(self): + """ + Test get_orgs_for_user using AuthZ compatibility layer + """ + role = CourseStaffRole(self.course_key) + + other_org = "MIT" + other_course_key = CourseKey.from_string(f"course-v1:{other_org}+Javascript+2026_T1") + another_course_key = CourseKey.from_string(f"course-v1:{other_org}+Python+2026_T1") + + staff_authz_role = RoleData(external_key=COURSE_STAFF) + instructor_authz_role = RoleData(external_key=COURSE_ADMIN) + + assignments = [ + RoleAssignmentData( + subject=UserData(external_key=self.student.username), + roles=[staff_authz_role], + scope=CourseOverviewData(external_key=str(self.course_key)), + ), + RoleAssignmentData( + subject=UserData(external_key=self.student.username), + roles=[staff_authz_role], + scope=CourseOverviewData(external_key=str(other_course_key)), + ), + RoleAssignmentData( + subject=UserData(external_key=self.student.username), + roles=[staff_authz_role], + scope=CourseOverviewData(external_key=str(another_course_key)), + ), + # Non-matching role should be ignored + RoleAssignmentData( + subject=UserData(external_key=self.student.username), + roles=[instructor_authz_role], + scope=CourseOverviewData(external_key=str(self.course_key)), + ), + ] + + 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.course_key.org, other_org]) + def test_get_authz_compat_course_access_roles_for_user(self): """ - Thest that get_authz_compat_course_access_roles_for_user doesn't crash when the user + Test that get_authz_compat_course_access_roles_for_user doesn't crash when the user has Libraries V2 or other non-course roles in their assignments. """ lib_assignment = RoleAssignmentData( diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 1f9df206f0ae..496211cab431 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -514,6 +514,7 @@ edx-opaque-keys[django]==3.1.0 edx-organizations==7.3.0 # via # -r requirements/edx/kernel.in + # openedx-authz # openedx-core edx-proctoring==5.2.0 # via -r requirements/edx/kernel.in @@ -823,7 +824,7 @@ openedx-atlas==0.7.0 # enterprise-integrated-channels # openedx-authz # openedx-forum -openedx-authz==1.0.0 +openedx-authz==1.2.0 # via -r requirements/edx/kernel.in openedx-calc==5.0.0 # via diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index f6f53b6041bb..4398f3686ca8 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -806,6 +806,7 @@ edx-organizations==7.3.0 # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt + # openedx-authz # openedx-core edx-proctoring==5.2.0 # via @@ -1373,7 +1374,7 @@ openedx-atlas==0.7.0 # enterprise-integrated-channels # openedx-authz # openedx-forum -openedx-authz==1.0.0 +openedx-authz==1.2.0 # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 99606f68983e..02ae81a93b86 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -605,6 +605,7 @@ edx-opaque-keys[django]==3.1.0 edx-organizations==7.3.0 # via # -r requirements/edx/base.txt + # openedx-authz # openedx-core edx-proctoring==5.2.0 # via -r requirements/edx/base.txt @@ -1001,7 +1002,7 @@ openedx-atlas==0.7.0 # enterprise-integrated-channels # openedx-authz # openedx-forum -openedx-authz==1.0.0 +openedx-authz==1.2.0 # via -r requirements/edx/base.txt openedx-calc==5.0.0 # via diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 5ce8448d174b..a68b55f91287 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -627,6 +627,7 @@ edx-opaque-keys[django]==3.1.0 edx-organizations==7.3.0 # via # -r requirements/edx/base.txt + # openedx-authz # openedx-core edx-proctoring==5.2.0 # via -r requirements/edx/base.txt @@ -1048,7 +1049,7 @@ openedx-atlas==0.7.0 # enterprise-integrated-channels # openedx-authz # openedx-forum -openedx-authz==1.0.0 +openedx-authz==1.2.0 # via -r requirements/edx/base.txt openedx-calc==5.0.0 # via