diff --git a/lms/djangoapps/courseware/masquerade.py b/lms/djangoapps/courseware/masquerade.py index 577833ecef..27ab111346 100644 --- a/lms/djangoapps/courseware/masquerade.py +++ b/lms/djangoapps/courseware/masquerade.py @@ -20,12 +20,17 @@ from pytz import utc from web_fragments.fragment import Fragment from xblock.runtime import KeyValueStore +from course_modes.models import CourseMode from openedx.core.djangoapps.util.user_messages import PageLevelMessages from openedx.core.djangolib.markup import HTML +from openedx.features.content_type_gating.helpers import CONTENT_GATING_PARTITION_ID +from openedx.features.content_type_gating.helpers import FULL_ACCESS +from openedx.features.content_type_gating.helpers import LIMITED_ACCESS from student.models import CourseEnrollment from student.role_helpers import has_staff_roles from util.json_request import JsonResponse, expect_json from xmodule.modulestore.django import modulestore +from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID from xmodule.partitions.partitions import NoSuchUserPartitionGroupError from xmodule.partitions.partitions_service import get_all_partitions_for_course @@ -229,6 +234,83 @@ def get_masquerade_role(user, course_key): return course_masquerade.role if course_masquerade else None +def _get_masquerade_group_id(target_user_partition_id, user, course_key, course_masquerade=None): + """ + Return the masqueraded track's group ID + if it's in the specified user partition, + otherwise, return None + """ + course_masquerade = course_masquerade or get_course_masquerade(user, course_key) + if course_masquerade is not None: + user_partition_id = course_masquerade.user_partition_id + if user_partition_id == target_user_partition_id: + group_id = course_masquerade.group_id + if group_id: + return group_id + return None + + +def is_masquerading(user, course_key, course_masquerade=None): + """ + Return if the user is masquerading at all + """ + course_masquerade = course_masquerade or get_course_masquerade(user, course_key) + _is_masquerading = course_masquerade is not None + return _is_masquerading + + +def is_masquerading_as_non_audit_enrollment(user, course_key, course_masquerade=None): + """ + Return if the user is a staff member masquerading as a user + in _any_ enrollment track _except_ audit + """ + group_id = _get_masquerade_group_id(ENROLLMENT_TRACK_PARTITION_ID, user, course_key, course_masquerade) + audit_mode_id = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.AUDIT, {}).get('id') + if group_id is not None: + if group_id != audit_mode_id: + return True + return False + + +def is_masquerading_as_audit_enrollment(user, course_key, course_masquerade=None): + """ + Return if the user is a staff member masquerading as a user + in the audit enrollment track + """ + group_id = _get_masquerade_group_id(ENROLLMENT_TRACK_PARTITION_ID, user, course_key, course_masquerade) + audit_mode_id = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.AUDIT, {}).get('id') + _is_masquerading = group_id == audit_mode_id + return _is_masquerading + + +def is_masquerading_as_full_access(user, course_key, course_masquerade=None): + """ + Return if the user is a staff member masquerading as a user + in the Full-Access track + """ + group_id = _get_masquerade_group_id(CONTENT_GATING_PARTITION_ID, user, course_key, course_masquerade) + _is_masquerading = group_id == FULL_ACCESS.id + return _is_masquerading + + +def is_masquerading_as_limited_access(user, course_key, course_masquerade=None): + """ + Return if the user is a staff member masquerading as a user + in the Limited-Access track + """ + group_id = _get_masquerade_group_id(CONTENT_GATING_PARTITION_ID, user, course_key, course_masquerade) + _is_masquerading = group_id == LIMITED_ACCESS.id + return _is_masquerading + + +def is_masquerading_as_staff(user, course_key): + """ + Return if the user is a staff member masquerading as user + that is itself a staff user + """ + return get_masquerade_role(user, course_key) == 'staff' + + def is_masquerading_as_student(user, course_key): """ Returns true if the user is a staff member masquerading as a student. @@ -270,8 +352,8 @@ def check_content_start_date_for_masquerade_user(course_key, user, request, cour most_future_date = course_start if chapter_start and section_start: most_future_date = max(course_start, chapter_start, section_start) - is_masquerading = get_course_masquerade(user, course_key) - if now < most_future_date and is_masquerading: + _is_masquerading = get_course_masquerade(user, course_key) + if now < most_future_date and _is_masquerading: group_masquerade = is_masquerading_as_student(user, course_key) specific_student_masquerade = is_masquerading_as_specific_student(user, course_key) is_staff = has_staff_roles(user, course_key) diff --git a/openedx/core/djangoapps/courseware_api/views.py b/openedx/core/djangoapps/courseware_api/views.py index 3f35294b4c..e7c35852a2 100644 --- a/openedx/core/djangoapps/courseware_api/views.py +++ b/openedx/core/djangoapps/courseware_api/views.py @@ -21,6 +21,13 @@ from edxnotes.helpers import is_feature_enabled 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 +from lms.djangoapps.courseware.masquerade import is_masquerading +from lms.djangoapps.courseware.masquerade import is_masquerading_as_audit_enrollment +from lms.djangoapps.courseware.masquerade import is_masquerading_as_full_access +from lms.djangoapps.courseware.masquerade import is_masquerading_as_limited_access +from lms.djangoapps.courseware.masquerade import is_masquerading_as_non_audit_enrollment +from lms.djangoapps.courseware.masquerade import is_masquerading_as_staff +from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.module_render import get_module_by_usage_id from lms.djangoapps.courseware.tabs import get_course_tab_list from lms.djangoapps.courseware.utils import can_show_verified_upgrade @@ -47,17 +54,21 @@ class CoursewareMeta: course_key, ) self.effective_user = self.overview.effective_user + # We need to memoize `is_staff` _before_ we configure masquerade. + self.is_staff = has_access(self.effective_user, 'staff', self.overview).has_access self.course_key = course_key self.enrollment_object = CourseEnrollment.get_enrollment(self.effective_user, self.course_key, select_related=['celebration']) + course_masquerade, _user = setup_masquerade( + request, + course_key, + staff_access=self.is_staff, + ) + self.course_masquerade = course_masquerade def __getattr__(self, name): return getattr(self.overview, name) - @property - def is_staff(self): - return has_access(self.effective_user, 'staff', self.overview).has_access - @property def enrollment(self): """ @@ -85,10 +96,27 @@ class CoursewareMeta: @property def content_type_gating_enabled(self): - return ContentTypeGatingConfig.enabled_for_enrollment( - user=self.effective_user, - course_key=self.course_key, - ) + course_key = self.course_key + user = self.effective_user + is_enabled = None + course_masquerade = self.course_masquerade + if is_masquerading(user, course_key, course_masquerade): + if is_masquerading_as_staff(user, course_key): + is_enabled = False + elif is_masquerading_as_full_access(user, course_key, course_masquerade): + is_enabled = False + elif is_masquerading_as_non_audit_enrollment(user, course_key, course_masquerade): + is_enabled = False + elif is_masquerading_as_audit_enrollment(user, course_key, course_masquerade): + is_enabled = ContentTypeGatingConfig.enabled_for_course(course_key) + elif is_masquerading_as_limited_access(user, course_key, course_masquerade): + is_enabled = ContentTypeGatingConfig.enabled_for_course(course_key) + if is_enabled is None: + is_enabled = ContentTypeGatingConfig.enabled_for_enrollment( + user=user, + course_key=course_key, + ) + return is_enabled @property def can_show_upgrade_sock(self):