Esempio n. 1
0
    def has_full_access_role_in_masquerade(cls, user, course_key, course_masquerade):
        """
        When masquerading, the course duration limits will never trigger the course to expire, redirecting the user.
        The roles of the masquerade user are still used to determine whether the course duration limit banner displays.
        Another banner also displays if the course is expired for the masquerade user.
        Both banners will appear if the masquerade user does not have any of the following roles:
        Staff, Instructor, Beta Tester, Forum Community TA, Forum Group Moderator, Forum Moderator, Forum Administrator
        """
        masquerade_role = get_masquerade_role(user, course_key)
        verified_mode_id = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.VERIFIED, {}).get('id')
        # Masquerading users can select the the role of a verified users without selecting a specific user
        is_verified = (course_masquerade.user_partition_id == ENROLLMENT_TRACK_PARTITION_ID
                       and course_masquerade.group_id == verified_mode_id)
        # Masquerading users can select the role of staff without selecting a specific user
        is_staff = masquerade_role == 'staff'
        # Masquerading users can select other full access roles for which content type gating is disabled
        is_full_access = (course_masquerade.user_partition_id == CONTENT_GATING_PARTITION_ID
                          and course_masquerade.group_id == CONTENT_TYPE_GATE_GROUP_IDS['full_access'])
        # When masquerading as a specific user, we can check that user's staff roles as we would with a normal user
        is_staff_role = False
        if course_masquerade.user_name:
            is_staff_role = has_staff_roles(user, course_key)

        if is_verified or is_full_access or is_staff or is_staff_role:
            return True
        return False
Esempio n. 2
0
def check_content_start_date_for_masquerade_user(course_key,
                                                 user,
                                                 request,
                                                 course_start,
                                                 chapter_start=None,
                                                 section_start=None):
    """
    Add a warning message if the masquerade user would not have access to this content
    due to the content start date being in the future.
    """
    now = datetime.now(utc)
    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:
        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)
        if group_masquerade or (specific_student_masquerade and not is_staff):
            PageLevelMessages.register_warning_message(
                request,
                HTML(
                    _('This user does not have access to this content because \
                        the content start date is in the future')),
                once_only=True)
Esempio n. 3
0
 def has_full_access_role_in_masquerade(cls, user, course_key, course_masquerade, student_masquerade,
                                        user_partition):
     """
     The roles of the masquerade user are used to determine whether the content gate displays.
     The gate will not appear if the masquerade user has any of the following roles:
     Staff, Instructor, Beta Tester, Forum Community TA, Forum Group Moderator, Forum Moderator, Forum Administrator
     """
     if student_masquerade:
         # If a request is masquerading as a specific user, the user variable will represent the correct user.
         if user and user.id and has_staff_roles(user, course_key):
             return True
     elif user_partition:
         # If the current user is masquerading as a generic student in a specific group,
         # then return the value based on that group.
         masquerade_group = get_masquerading_user_group(course_key, user, user_partition)
         if masquerade_group is None:
             audit_mode_id = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.AUDIT, {}).get('id')
             # We are checking the user partition id here because currently content
             # cannot have both the enrollment track partition and content gating partition
             # configured simultaneously. We may change this in the future and allow
             # configuring both partitions on content and selecting both partitions in masquerade.
             if course_masquerade.user_partition_id == ENROLLMENT_TRACK_PARTITION_ID:
                 return course_masquerade.group_id != audit_mode_id
         elif masquerade_group is FULL_ACCESS:
             return True
         elif masquerade_group is LIMITED_ACCESS:
             return False
Esempio n. 4
0
    def has_full_access_role_in_masquerade(cls, user, course_key, course_masquerade):
        """
        When masquerading, the course duration limits will never trigger the course to expire, redirecting the user.
        The roles of the masquerade user are still used to determine whether the course duration limit banner displays.
        Another banner also displays if the course is expired for the masquerade user.
        Both banners will appear if the masquerade user does not have any of the following roles:
        Staff, Instructor, Beta Tester, Forum Community TA, Forum Group Moderator, Forum Moderator, Forum Administrator
        """
        masquerade_role = get_masquerade_role(user, course_key)
        verified_mode_id = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.VERIFIED, {}).get('id')
        # Masquerading users can select the the role of a verified users without selecting a specific user
        is_verified = (course_masquerade.user_partition_id == ENROLLMENT_TRACK_PARTITION_ID
                       and course_masquerade.group_id == verified_mode_id)
        # Masquerading users can select the role of staff without selecting a specific user
        is_staff = masquerade_role == 'staff'
        # Masquerading users can select other full access roles for which content type gating is disabled
        is_full_access = (course_masquerade.user_partition_id == CONTENT_GATING_PARTITION_ID
                          and course_masquerade.group_id == CONTENT_TYPE_GATE_GROUP_IDS['full_access'])
        # When masquerading as a specific user, we can check that user's staff roles as we would with a normal user
        is_staff_role = False
        if course_masquerade.user_name:
            is_staff_role = has_staff_roles(user, course_key)

        if is_verified or is_full_access or is_staff or is_staff_role:
            return True
        return False
Esempio n. 5
0
 def get(self, request, course_key_string):
     """
     Retrieve data on the active and available masquerade options
     """
     course_key = CourseKey.from_string(course_key_string)
     is_staff = has_staff_roles(request.user, course_key)
     if not is_staff:
         return JsonResponse({
             'success': False,
         })
     masquerade_settings = request.session.get(MASQUERADE_SETTINGS_KEY, {})
     course = masquerade_settings.get(course_key, None)
     course = course or CourseMasquerade(
         course_key,
         role='staff',
         user_partition_id=None,
         group_id=None,
         user_name=None,
     )
     descriptor = modulestore().get_course(course_key)
     partitions = get_all_partitions_for_course(descriptor,
                                                active_only=True)
     data = {
         'success':
         True,
         'active': {
             'course_key': course_key_string,
             'group_id': course.group_id,
             'role': course.role,
             'user_name': course.user_name or None,
             'user_partition_id': course.user_partition_id,
         },
         'available': [
             {
                 'name': 'Staff',
                 'role': 'staff',
             },
             {
                 'name': 'Learner',
                 'role': 'student',
             },
             {
                 'name': 'Specific Student...',
                 'role': 'student',
                 'user_name': course.user_name or '',
             },
         ],
     }
     for partition in partitions:
         if partition.active:
             data['available'].extend([{
                 'group_id': group.id,
                 'name': group.name,
                 'role': 'student',
                 'user_partition_id': partition.id,
             } for group in partition.groups])
     data['active']['group_name'] = course.get_active_group_name(
         data['available'])
     return JsonResponse(data)
Esempio n. 6
0
    def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None, user_partition=None):
        """
        Return whether Content Type Gating is enabled for this enrollment.

        Content Type Gating is enabled for an enrollment if it is enabled for
        the course being enrolled in (either specifically, or via a containing context,
        such as the org, site, or globally), and if the configuration is specified to be
        ``enabled_as_of`` before the enrollment was created.

        Only one of enrollment and (user, course_key) may be specified at a time.

        Arguments:
            enrollment: The enrollment being queried.
            user: The user being queried.
            course_key: The CourseKey of the course being queried.
        """
        if enrollment is not None and (user is not None or course_key is not None):
            raise ValueError('Specify enrollment or user/course_key, but not both')

        if enrollment is None and (user is None or course_key is None):
            raise ValueError('Both user and course_key must be specified if no enrollment is provided')

        if enrollment is None and user is None and course_key is None:
            raise ValueError('At least one of enrollment or user and course_key must be specified')

        if course_key is None:
            course_key = enrollment.course_id

        if enrollment is None:
            enrollment = CourseEnrollment.get_enrollment(user, course_key)

        if user is None and enrollment is not None:
            user = enrollment.user

        course_masquerade = get_course_masquerade(user, course_key)
        no_masquerade = course_masquerade is None
        student_masquerade = is_masquerading_as_specific_student(user, course_key)
        user_variable_represents_correct_user = (no_masquerade or student_masquerade)

        if course_masquerade:
            if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade, student_masquerade,
                                                      user_partition):
                return False
        # When a request is not in a masquerade state the user variable represents the correct user.
        elif user and user.id and has_staff_roles(user, course_key):
            return False

        # check if user is in holdback
        if user_variable_represents_correct_user and is_in_holdback(user):
            return False

        # enrollment might be None if the user isn't enrolled. In that case,
        # return enablement as if the user enrolled today
        # Also, ignore enrollment creation date if the user is masquerading.
        if enrollment is None or course_masquerade:
            return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now())
        else:
            current_config = cls.current(course_key=enrollment.course_id)
            return current_config.enabled_as_of_datetime(target_datetime=enrollment.created)
Esempio n. 7
0
    def enabled_for_enrollment(cls, user=None, course_key=None):
        """
        Return whether Course Duration Limits are enabled for this enrollment.

        Course Duration Limits are enabled for an enrollment if they are enabled for
        the course being enrolled in (either specifically, or via a containing context,
        such as the org, site, or globally), and if the configuration is specified to be
        ``enabled_as_of`` before the enrollment was created.

        Only one of enrollment and (user, course_key) may be specified at a time.

        Arguments:
            enrollment: The enrollment being queried.
            user: The user being queried.
            course_key: The CourseKey of the course being queried.
        """

        if user is None or course_key is None:
            raise ValueError('Both user and course_key must be specified if no enrollment is provided')

        enrollment = CourseEnrollment.get_enrollment(user, course_key, ['fbeenrollmentexclusion'])

        if user is None and enrollment is not None:
            user = enrollment.user

        if user and user.id:
            course_masquerade = get_course_masquerade(user, course_key)
            if course_masquerade:
                if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade):
                    return False
            elif has_staff_roles(user, course_key):
                return False

        is_masquerading = get_course_masquerade(user, course_key)
        no_masquerade = is_masquerading is None
        student_masquerade = is_masquerading_as_specific_student(user, course_key)

        # check if user is in holdback
        if (no_masquerade or student_masquerade) and is_in_holdback(user, enrollment):
            return False

        not_student_masquerade = is_masquerading and not student_masquerade

        # enrollment might be None if the user isn't enrolled. In that case,
        # return enablement as if the user enrolled today
        # When masquerading as a user group rather than a specific learner,
        # course duration limits will be on if they are on for the course.
        # When masquerading as a specific learner, course duration limits
        # will be on if they are currently on for the learner.
        if enrollment is None or not_student_masquerade:
            # we bypass enabled_for_course here and use enabled_as_of_datetime directly
            # because the correct_modes_for_fbe for FBE check contained in enabled_for_course
            # is redundant with checks done upstream of this code
            target_datetime = timezone.now()
        else:
            target_datetime = enrollment.created
        current_config = cls.current(course_key=course_key)
        return current_config.enabled_as_of_datetime(target_datetime=target_datetime)
Esempio n. 8
0
 def post(self, request, course_key_string):
     """
     Handle AJAX posts to update the current user's masquerade for the specified course.
     The masquerade settings are stored in the Django session as a dict from course keys
     to CourseMasquerade objects.
     """
     course_key = CourseKey.from_string(course_key_string)
     is_staff = has_staff_roles(request.user, course_key)
     if not is_staff:
         return JsonResponse({
             'success': False,
         })
     masquerade_settings = request.session.get(MASQUERADE_SETTINGS_KEY, {})
     request_json = request.json
     role = request_json.get('role', 'student')
     group_id = request_json.get('group_id', None)
     user_partition_id = request_json.get(
         'user_partition_id', None) if group_id is not None else None
     user_name = request_json.get('user_name', None)
     found_user_name = None
     if user_name:
         users_in_course = CourseEnrollment.objects.users_enrolled_in(
             course_key)
         try:
             found_user_name = users_in_course.get(
                 Q(email=user_name) | Q(username=user_name)).username
         except User.DoesNotExist:
             return JsonResponse({
                 'success':
                 False,
                 'error':
                 _(u'There is no user with the username or email address "{user_identifier}" '
                   'enrolled in this course.').format(
                       user_identifier=user_name, ),
             })
     masquerade_settings[course_key] = CourseMasquerade(
         course_key,
         role=role,
         user_partition_id=user_partition_id,
         group_id=group_id,
         user_name=found_user_name,
     )
     request.session[MASQUERADE_SETTINGS_KEY] = masquerade_settings
     return JsonResponse({'success': True})
def check_start_date(user, days_early_for_beta, start, course_key):
    """
    Verifies whether the given user is allowed access given the
    start date and the Beta offset for the given course.

    Returns:
        AccessResponse: Either ACCESS_GRANTED or StartDateError.
    """
    start_dates_disabled = settings.FEATURES['DISABLE_START_DATES']
    masquerading_as_student = is_masquerading_as_student(user, course_key)
    masquerading_as_specific_student = is_masquerading_as_specific_student(
        user, course_key)

    if start_dates_disabled and not masquerading_as_student:
        return ACCESS_GRANTED
    else:
        now = datetime.now(UTC)
        if start is None or in_preview_mode():
            return ACCESS_GRANTED

        effective_start = adjust_start_date(user, days_early_for_beta, start,
                                            course_key)
        if now > effective_start:
            return ACCESS_GRANTED

        if get_course_masquerade(user, course_key):
            if masquerading_as_student or (
                    masquerading_as_specific_student
                    and not has_staff_roles(user, course_key)):
                request = get_current_request()
                PageLevelMessages.register_warning_message(
                    request,
                    HTML(
                        _('This user does not have access to this content due to the content start date'
                          )),
                    once_only=True)
                return ACCESS_GRANTED

        return StartDateError(start)
Esempio n. 10
0
def check_content_start_date_for_masquerade_user(course_key, user, request, course_start,
                                                 chapter_start=None, section_start=None):
    """
    Add a warning message if the masquerade user would not have access to this content
    due to the content start date being in the future.
    """
    now = datetime.now(utc)
    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:
        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)
        if group_masquerade or (specific_student_masquerade and not is_staff):
            PageLevelMessages.register_warning_message(
                request,
                HTML(_('This user does not have access to this content because \
                        the content start date is in the future')),
                once_only=True
            )
Esempio n. 11
0
    def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None):
        """
        Return whether Course Duration Limits are enabled for this enrollment.

        Course Duration Limits are enabled for an enrollment if they are enabled for
        the course being enrolled in (either specifically, or via a containing context,
        such as the org, site, or globally), and if the configuration is specified to be
        ``enabled_as_of`` before the enrollment was created.

        Only one of enrollment and (user, course_key) may be specified at a time.

        Arguments:
            enrollment: The enrollment being queried.
            user: The user being queried.
            course_key: The CourseKey of the course being queried.
        """

        if FEATURE_BASED_ENROLLMENT_GLOBAL_KILL_FLAG.is_enabled():
            return False

        if CONTENT_TYPE_GATING_FLAG.is_enabled():
            return True

        if enrollment is not None and (user is not None or course_key is not None):
            raise ValueError('Specify enrollment or user/course_key, but not both')

        if enrollment is None and (user is None or course_key is None):
            raise ValueError('Both user and course_key must be specified if no enrollment is provided')

        if enrollment is None and user is None and course_key is None:
            raise ValueError('At least one of enrollment or user and course_key must be specified')

        if course_key is None:
            course_key = enrollment.course_id

        if enrollment is None:
            enrollment = CourseEnrollment.get_enrollment(user, course_key)

        if user is None and enrollment is not None:
            user = enrollment.user

        if user and user.id:
            course_masquerade = get_course_masquerade(user, course_key)
            if course_masquerade:
                if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade):
                    return False
            elif has_staff_roles(user, course_key):
                return False

        is_masquerading = get_course_masquerade(user, course_key)
        no_masquerade = is_masquerading is None
        student_masquerade = is_masquerading_as_specific_student(user, course_key)

        # check if user is in holdback
        if (no_masquerade or student_masquerade) and is_in_holdback(user):
            return False

        not_student_masquerade = is_masquerading and not student_masquerade

        # enrollment might be None if the user isn't enrolled. In that case,
        # return enablement as if the user enrolled today
        # When masquerading as a user group rather than a specific learner,
        # course duration limits will be on if they are on for the course.
        # When masquerading as a specific learner, course duration limits
        # will be on if they are currently on for the learner.
        if enrollment is None or not_student_masquerade:
            return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now())
        else:
            current_config = cls.current(course_key=enrollment.course_id)
            return current_config.enabled_as_of_datetime(target_datetime=enrollment.created)
Esempio n. 12
0
    def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None, user_partition=None):
        """
        Return whether Content Type Gating is enabled for this enrollment.

        Content Type Gating is enabled for an enrollment if it is enabled for
        the course being enrolled in (either specifically, or via a containing context,
        such as the org, site, or globally), and if the configuration is specified to be
        ``enabled_as_of`` before the enrollment was created.

        Only one of enrollment and (user, course_key) may be specified at a time.

        Arguments:
            enrollment: The enrollment being queried.
            user: The user being queried.
            course_key: The CourseKey of the course being queried.
        """
        if enrollment is not None and (user is not None or course_key is not None):
            raise ValueError('Specify enrollment or user/course_key, but not both')

        if enrollment is None and (user is None or course_key is None):
            raise ValueError('Both user and course_key must be specified if no enrollment is provided')

        if enrollment is None and user is None and course_key is None:
            raise ValueError('At least one of enrollment or user and course_key must be specified')

        if course_key is None:
            course_key = enrollment.course_id

        if enrollment is None:
            enrollment = CourseEnrollment.get_enrollment(user, course_key)

        if user is None and enrollment is not None:
            user = enrollment.user

        course_masquerade = get_course_masquerade(user, course_key)
        no_masquerade = course_masquerade is None
        student_masquerade = is_masquerading_as_specific_student(user, course_key)
        user_variable_represents_correct_user = (no_masquerade or student_masquerade)

        if course_masquerade:
            if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade, student_masquerade,
                                                      user_partition):
                return False
        # When a request is not in a masquerade state the user variable represents the correct user.
        elif user and user.id and has_staff_roles(user, course_key):
            return False

        # check if user is in holdback
        if user_variable_represents_correct_user and is_in_holdback(user):
            return False

        if not correct_modes_for_fbe(course_key, enrollment, user):
            return False

        # enrollment might be None if the user isn't enrolled. In that case,
        # return enablement as if the user enrolled today
        # Also, ignore enrollment creation date if the user is masquerading.
        if enrollment is None or course_masquerade:
            target_datetime = timezone.now()
        else:
            target_datetime = enrollment.created
        current_config = cls.current(course_key=course_key)
        return current_config.enabled_as_of_datetime(target_datetime=target_datetime)
Esempio n. 13
0
    def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None):
        """
        Return whether Course Duration Limits are enabled for this enrollment.

        Course Duration Limits are enabled for an enrollment if they are enabled for
        the course being enrolled in (either specifically, or via a containing context,
        such as the org, site, or globally), and if the configuration is specified to be
        ``enabled_as_of`` before the enrollment was created.

        Only one of enrollment and (user, course_key) may be specified at a time.

        Arguments:
            enrollment: The enrollment being queried.
            user: The user being queried.
            course_key: The CourseKey of the course being queried.
        """

        if enrollment is not None and (user is not None or course_key is not None):
            raise ValueError('Specify enrollment or user/course_key, but not both')

        if enrollment is None and (user is None or course_key is None):
            raise ValueError('Both user and course_key must be specified if no enrollment is provided')

        if enrollment is None and user is None and course_key is None:
            raise ValueError('At least one of enrollment or user and course_key must be specified')

        if course_key is None:
            course_key = enrollment.course_id

        if enrollment is None:
            enrollment = CourseEnrollment.get_enrollment(user, course_key)

        if user is None and enrollment is not None:
            user = enrollment.user

        if user and user.id:
            course_masquerade = get_course_masquerade(user, course_key)
            if course_masquerade:
                if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade):
                    return False
            elif has_staff_roles(user, course_key):
                return False

        is_masquerading = get_course_masquerade(user, course_key)
        no_masquerade = is_masquerading is None
        student_masquerade = is_masquerading_as_specific_student(user, course_key)

        # check if user is in holdback
        if (no_masquerade or student_masquerade) and is_in_holdback(user):
            return False

        not_student_masquerade = is_masquerading and not student_masquerade

        # enrollment might be None if the user isn't enrolled. In that case,
        # return enablement as if the user enrolled today
        # When masquerading as a user group rather than a specific learner,
        # course duration limits will be on if they are on for the course.
        # When masquerading as a specific learner, course duration limits
        # will be on if they are currently on for the learner.
        if enrollment is None or not_student_masquerade:
            # we bypass enabled_for_course here and use enabled_as_of_datetime directly
            # because the correct_modes_for_fbe for FBE check contained in enabled_for_course
            # is redundant with checks done upstream of this code
            target_datetime = timezone.now()
        else:
            target_datetime = enrollment.created
        current_config = cls.current(course_key=course_key)
        return current_config.enabled_as_of_datetime(target_datetime=target_datetime)