From bc10352f1519897025e8f1345a13b657e6eba3e9 Mon Sep 17 00:00:00 2001 From: 0x29a Date: Thu, 5 Sep 2024 12:20:25 +0200 Subject: [PATCH] feat: add has_course_author_access to CourseHomeMetadataView response Cherry-picked from https://github.com/openedx/edx-platform/pull/35313 --- common/djangoapps/student/auth.py | 14 ++++---- .../course_metadata/serializers.py | 1 + .../course_metadata/tests/test_views.py | 36 ++++++++++++++++++- .../course_home_api/course_metadata/views.py | 7 ++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/common/djangoapps/student/auth.py b/common/djangoapps/student/auth.py index d3dc51616c75..de9ccfc7bf2f 100644 --- a/common/djangoapps/student/auth.py +++ b/common/djangoapps/student/auth.py @@ -73,7 +73,7 @@ def user_has_role(user, role): return False -def get_user_permissions(user, course_key, org=None): +def get_user_permissions(user, course_key, org=None, service_variant=None): """ Get the bitmask of permissions that this user has in the given course context. Can also set course_key=None and pass in an org to get the user's @@ -103,7 +103,7 @@ def get_user_permissions(user, course_key, org=None): # the LMS and Studio permissions will be separated as a part of this project. Once this is done (and this code is # not removed during its implementation), we can replace the Limited Staff permissions with more granular ones. if course_key and user_has_role(user, CourseLimitedStaffRole(course_key)): - if settings.SERVICE_VARIANT == 'lms': + if (service_variant or settings.SERVICE_VARIANT) == 'lms': return STUDIO_EDIT_CONTENT else: return STUDIO_NO_PERMISSIONS @@ -119,7 +119,7 @@ def get_user_permissions(user, course_key, org=None): return STUDIO_NO_PERMISSIONS -def has_studio_write_access(user, course_key): +def has_studio_write_access(user, course_key, service_variant=None): """ Return True if user has studio write access to the given course. Note that the CMS permissions model is with respect to courses. @@ -131,15 +131,17 @@ def has_studio_write_access(user, course_key): :param user: :param course_key: a CourseKey + :param service_variant: the variant of the service (lms or cms). Permissions may differ between the two, + see the comment in get_user_permissions for more details. """ - return bool(STUDIO_EDIT_CONTENT & get_user_permissions(user, course_key)) + return bool(STUDIO_EDIT_CONTENT & get_user_permissions(user, course_key, service_variant=service_variant)) -def has_course_author_access(user, course_key): +def has_course_author_access(user, course_key, service_variant=None): """ Old name for has_studio_write_access """ - return has_studio_write_access(user, course_key) + return has_studio_write_access(user, course_key, service_variant) def has_studio_advanced_settings_access(user): diff --git a/lms/djangoapps/course_home_api/course_metadata/serializers.py b/lms/djangoapps/course_home_api/course_metadata/serializers.py index 7683a9089453..ccb22e86b9fa 100644 --- a/lms/djangoapps/course_home_api/course_metadata/serializers.py +++ b/lms/djangoapps/course_home_api/course_metadata/serializers.py @@ -58,3 +58,4 @@ class CourseHomeMetadataSerializer(VerifiedModeSerializer): can_view_certificate = serializers.BooleanField() course_modes = CourseModeSerrializer(many=True) is_new_discussion_sidebar_view_enabled = serializers.BooleanField() + has_course_author_access = serializers.BooleanField() diff --git a/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py b/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py index 4b3524eb1ee2..86aeee883a7c 100644 --- a/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py +++ b/lms/djangoapps/course_home_api/course_metadata/tests/test_views.py @@ -12,7 +12,12 @@ from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.student.models import CourseEnrollment -from common.djangoapps.student.roles import CourseInstructorRole +from common.djangoapps.student.roles import ( + CourseBetaTesterRole, + CourseInstructorRole, + CourseLimitedStaffRole, + CourseStaffRole +) from common.djangoapps.student.tests.factories import UserFactory from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests from lms.djangoapps.courseware.toggles import ( @@ -248,3 +253,32 @@ def test_discussion_tab_visible(self, visible): assert 'discussion' in tab_ids else: assert 'discussion' not in tab_ids + + @ddt.data( + { + 'course_team_role': None, + 'has_course_author_access': False + }, + { + 'course_team_role': CourseBetaTesterRole, + 'has_course_author_access': False + }, + { + 'course_team_role': CourseStaffRole, + 'has_course_author_access': True + }, + { + 'course_team_role': CourseLimitedStaffRole, + 'has_course_author_access': False + }, + ) + @ddt.unpack + def test_has_course_author_access_for_staff_roles(self, course_team_role, has_course_author_access): + CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED) + + if course_team_role: + course_team_role(self.course.id).add_users(self.user) + + response = self.client.get(self.url) + assert response.status_code == 200 + assert response.data['has_course_author_access'] == has_course_author_access diff --git a/lms/djangoapps/course_home_api/course_metadata/views.py b/lms/djangoapps/course_home_api/course_metadata/views.py index 248f90389d40..7ad2a2537000 100644 --- a/lms/djangoapps/course_home_api/course_metadata/views.py +++ b/lms/djangoapps/course_home_api/course_metadata/views.py @@ -16,6 +16,7 @@ from openedx.core.djangoapps.courseware_api.utils import get_celebrations_dict from common.djangoapps.course_modes.models import CourseMode +from common.djangoapps.student.auth import has_course_author_access from common.djangoapps.student.models import CourseEnrollment from lms.djangoapps.course_api.api import course_detail from lms.djangoapps.course_goals.models import UserActivity @@ -139,6 +140,12 @@ def get(self, request, *args, **kwargs): 'can_view_certificate': certificates_viewable_for_course(course), 'course_modes': course_modes, 'is_new_discussion_sidebar_view_enabled': new_discussion_sidebar_view_is_enabled(course_key), + # We check the course author access in the context of CMS here because this field is used + # to determine whether the user can access the course authoring tools in the CMS. + # This is a temporary solution until the course author role is split into "Course Author" and + # "Course Editor" as described in the permission matrix here: + # https://github.com/openedx/platform-roadmap/issues/246 + 'has_course_author_access': has_course_author_access(request.user, course_key, 'cms'), } context = self.get_serializer_context() context['course'] = course