From f1ed047af50e0c56dc04b9ecf8b4454392e0c380 Mon Sep 17 00:00:00 2001 From: Tehreem Sadat Date: Thu, 2 Jan 2025 02:25:55 +1300 Subject: [PATCH] feat: move progress related apis permissions to standard permission file so it can be override for data researchers --- .../course_metadata/permissions.py | 34 +++++++++++++++++++ .../course_home_api/course_metadata/views.py | 23 +++++-------- .../course_home_api/progress/permissions.py | 21 ++++++++++++ .../course_home_api/progress/views.py | 5 +-- 4 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 lms/djangoapps/course_home_api/course_metadata/permissions.py create mode 100644 lms/djangoapps/course_home_api/progress/permissions.py diff --git a/lms/djangoapps/course_home_api/course_metadata/permissions.py b/lms/djangoapps/course_home_api/course_metadata/permissions.py new file mode 100644 index 000000000000..e600da3ca16a --- /dev/null +++ b/lms/djangoapps/course_home_api/course_metadata/permissions.py @@ -0,0 +1,34 @@ +from opaque_keys.edx.keys import CourseKey + +from rest_framework.permissions import BasePermission + +from lms.djangoapps.course_api.api import course_detail +from lms.djangoapps.courseware.access import has_access +from lms.djangoapps.courseware.courses import check_course_access + + +class HasCourseLoadPermission(BasePermission): + """ + Permission to check if the user has load access to the course. + """ + def has_permission(self, request, view): + course_key_string = view.kwargs.get('course_key_string') + course_key = CourseKey.from_string(course_key_string) + course = course_detail(request, request.user.username, course_key) + + # Check course load access + load_access = check_course_access( + course, + request.user, + 'load', + check_if_enrolled=True, + check_if_authenticated=True, + apply_enterprise_checks=True, + ) + + if not load_access.has_access: + return False + + request.course_load_access = load_access.to_json() + request.user_has_staff_access = has_access(request.user, 'staff', course_key).has_access + return True diff --git a/lms/djangoapps/course_home_api/course_metadata/views.py b/lms/djangoapps/course_home_api/course_metadata/views.py index e534d03ebbf7..9bfac5dcd45e 100644 --- a/lms/djangoapps/course_home_api/course_metadata/views.py +++ b/lms/djangoapps/course_home_api/course_metadata/views.py @@ -16,9 +16,9 @@ from lms.djangoapps.course_api.api import course_detail from lms.djangoapps.course_goals.models import UserActivity from lms.djangoapps.course_home_api.course_metadata.serializers import CourseHomeMetadataSerializer +from lms.djangoapps.course_home_api.course_metadata.permissions import HasCourseLoadPermission from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.context_processor import user_timezone_locale_prefs -from lms.djangoapps.courseware.courses import check_course_access from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.tabs import get_course_tab_list @@ -69,28 +69,21 @@ class CourseHomeMetadataView(RetrieveAPIView): SessionAuthenticationAllowInactiveUser, ) + # We must compute course load access *before* setting up masquerading, + # else course staff (who are not enrolled) will not be able view + # their course from the perspective of a learner. + permission_classes = (HasCourseLoadPermission,) + serializer_class = CourseHomeMetadataSerializer def get(self, request, *args, **kwargs): course_key_string = kwargs.get('course_key_string') course_key = CourseKey.from_string(course_key_string) original_user_is_global_staff = self.request.user.is_staff - original_user_is_staff = has_access(request.user, 'staff', course_key).has_access + original_user_is_staff = request.user_has_staff_access course = course_detail(request, request.user.username, course_key) - # We must compute course load access *before* setting up masquerading, - # else course staff (who are not enrolled) will not be able view - # their course from the perspective of a learner. - load_access = check_course_access( - course, - request.user, - 'load', - check_if_enrolled=True, - check_if_authenticated=True, - apply_enterprise_checks=True, - ) - _, request.user = setup_masquerade( request, course_key, @@ -126,7 +119,7 @@ def get(self, request, *args, **kwargs): 'title': course.display_name_with_default, 'is_self_paced': getattr(course, 'self_paced', False), 'is_enrolled': user_is_enrolled, - 'course_access': load_access.to_json(), + 'course_access': self.request.course_load_access, 'celebrations': celebrations, 'user_timezone': user_timezone, 'can_view_certificate': certificates_viewable_for_course(course), diff --git a/lms/djangoapps/course_home_api/progress/permissions.py b/lms/djangoapps/course_home_api/progress/permissions.py new file mode 100644 index 000000000000..d743339ccb88 --- /dev/null +++ b/lms/djangoapps/course_home_api/progress/permissions.py @@ -0,0 +1,21 @@ +from opaque_keys.edx.keys import CourseKey + +from rest_framework.permissions import BasePermission +from lms.djangoapps.courseware.access import has_access +from lms.djangoapps.course_api.api import course_detail + + +class HasProgressTabAccess(BasePermission): + """ + Permission to check if the user has load access + """ + + def has_permission(self, request, view): + course_key_string = view.kwargs.get('course_key_string') + course_key = CourseKey.from_string(course_key_string) + is_staff = bool(has_access(request.user, 'staff', course_key)) + course = course_detail(request, request.user.username, course_key) + if is_staff or bool(has_access(request.user, 'load', course)): + request.has_progress_tab_staff_access = is_staff + return True + return False diff --git a/lms/djangoapps/course_home_api/progress/views.py b/lms/djangoapps/course_home_api/progress/views.py index dc0ea63525f7..c11642c82902 100644 --- a/lms/djangoapps/course_home_api/progress/views.py +++ b/lms/djangoapps/course_home_api/progress/views.py @@ -26,6 +26,7 @@ ) from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.views.views import credit_course_requirements, get_cert_data +from lms.djangoapps.course_home_api.progress.permissions import HasProgressTabAccess from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.verify_student.services import IDVerificationService @@ -136,7 +137,7 @@ class ProgressTabView(RetrieveAPIView): BearerAuthenticationAllowInactiveUser, SessionAuthenticationAllowInactiveUser, ) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, HasProgressTabAccess,) serializer_class = ProgressTabSerializer def _get_student_user(self, request, course_key, student_id, is_staff): @@ -185,7 +186,7 @@ def get(self, request, *args, **kwargs): monitoring_utils.set_custom_attribute('course_id', course_key_string) monitoring_utils.set_custom_attribute('user_id', request.user.id) monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff) - is_staff = bool(has_access(request.user, 'staff', course_key)) + is_staff = request.has_progress_tab_staff_access student = self._get_student_user(request, course_key, student_id, is_staff) username = get_enterprise_learner_generic_name(request) or student.username