Exemplo n.º 1
0
def masquerade_as_group_member(user, course, partition_id, group_id):
    """
    Installs a masquerade for the specified user and course, to enable
    the user to masquerade as belonging to the specific partition/group
    combination.

    Arguments:
        user (User): a user.
        course (CourseDescriptor): a course.
        partition_id (int): the integer partition id, referring to partitions already
           configured in the course.
        group_id (int); the integer group id, within the specified partition.

    Returns: the status code for the AJAX response to update the user's masquerade for
        the specified course.
    """
    request = _create_mock_json_request(user,
                                        data={
                                            "role": "student",
                                            "user_partition_id": partition_id,
                                            "group_id": group_id
                                        })
    response = MasqueradeView.as_view()(request, six.text_type(course.id))
    setup_masquerade(request, course.id, True)
    return response.status_code
Exemplo n.º 2
0
    def _determine_user(self, request, course_key: CourseKey) -> types.User:
        """
        For which user should we get an outline?

        Uses a combination of the user on the request object, session masquerading
        data, and a manually passed in "user" parameter. Ensures that the requesting
        user has permission to view course outline of target user. Raise request-level
        exceptions otherwise.

        The "user" querystring param is expected to be a username, with a blank
        value being interpreted as the anonymous user. It will take priority over
        session masquerading, if provided.
        """
        has_staff_access = has_access(request.user, 'staff',
                                      course_key).has_access

        target_username = request.GET.get("user")
        if target_username is not None:
            target_user = self._get_target_user(request, course_key,
                                                has_staff_access,
                                                target_username)
            # Just like in masquerading, set real_user so that the
            # SafeSessions middleware can see that the user didn't
            # change unexpectedly.
            target_user.real_user = request.user
            return target_user

        _course_masquerade, user = setup_masquerade(request, course_key,
                                                    has_staff_access)
        return user
Exemplo n.º 3
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)

        if course_home_legacy_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        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)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        is_staff = bool(has_access(request.user, 'staff', course_key))

        _, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=is_staff,
            reset_masquerade_data=True,
        )

        if not CourseEnrollment.is_enrolled(request.user,
                                            course_key) and not is_staff:
            return Response('User not enrolled.', status=401)

        blocks = get_course_date_blocks(course,
                                        request.user,
                                        request,
                                        include_access=True,
                                        include_past_dates=True)

        learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment(
            user=request.user,
            course_key=course_key,
        )

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        data = {
            'has_ended':
            course.has_ended(),
            'course_date_blocks':
            [block for block in blocks if not isinstance(block, TodaysDate)],
            'learner_is_full_access':
            learner_is_full_access,
            'user_timezone':
            user_timezone,
        }
        context = self.get_serializer_context()
        context['learner_is_full_access'] = learner_is_full_access
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Exemplo n.º 4
0
 def __init__(self, course_key, request, username=''):
     self.request = request
     self.overview = course_detail(
         self.request,
         username or self.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.
     self.load_access = check_course_access(
         self.overview,
         self.request.user,
         'load',
         check_if_enrolled=True,
         check_if_authenticated=True,
     )
     self.original_user_is_staff = has_access(self.request.user, 'staff', self.overview).has_access
     self.original_user_is_global_staff = self.request.user.is_staff
     self.course_key = course_key
     self.course = get_course_by_id(self.course_key)
     self.course_masquerade, self.effective_user = setup_masquerade(
         self.request,
         course_key,
         staff_access=self.original_user_is_staff,
     )
     self.request.user = self.effective_user
     self.is_staff = has_access(self.effective_user, 'staff', self.overview).has_access
     self.enrollment_object = CourseEnrollment.get_enrollment(self.effective_user, self.course_key,
                                                              select_related=['celebration', 'user__celebration'])
     self.can_view_legacy_courseware = courseware_legacy_is_visible(
         course_key=course_key,
         is_global_staff=self.original_user_is_global_staff,
     )
Exemplo n.º 5
0
    def get(self, request, usage_key_string, *args, **kwargs):  # lint-amnesty, pylint: disable=unused-argument
        """
        Return response to a GET request.
        """
        try:
            usage_key = UsageKey.from_string(usage_key_string)
        except InvalidKeyError:
            raise NotFound(f"Invalid usage key: '{usage_key_string}'.")  # lint-amnesty, pylint: disable=raise-missing-from

        _, request.user = setup_masquerade(
            request,
            usage_key.course_key,
            staff_access=has_access(request.user, 'staff', usage_key.course_key),
            reset_masquerade_data=True,
        )

        sequence, _ = get_module_by_usage_id(
            self.request,
            str(usage_key.course_key),
            str(usage_key),
            disable_staff_debug_info=True,
            will_recheck_access=True)

        view = STUDENT_VIEW
        if request.user.is_anonymous:
            view = PUBLIC_VIEW

        context = {'specific_masquerade': is_masquerading_as_specific_student(request.user, usage_key.course_key)}
        return Response(sequence.get_metadata(view=view, context=context))
Exemplo n.º 6
0
    def get(self, request, usage_key_string, *args, **kwargs):  # lint-amnesty, pylint: disable=unused-argument
        """
        Return response to a GET request.
        """
        try:
            usage_key = UsageKey.from_string(usage_key_string)
        except InvalidKeyError as exc:
            raise NotFound(f"Invalid usage key: '{usage_key_string}'.") from exc
        _, request.user = setup_masquerade(
            request,
            usage_key.course_key,
            staff_access=has_access(request.user, 'staff', usage_key.course_key),
            reset_masquerade_data=True,
        )

        sequence, _ = get_module_by_usage_id(
            self.request,
            str(usage_key.course_key),
            str(usage_key),
            disable_staff_debug_info=True,
            will_recheck_access=True)

        if not hasattr(sequence, 'get_metadata'):
            # Looks like we were asked for metadata on something that is not a sequence (or section).
            return Response(status=status.HTTP_422_UNPROCESSABLE_ENTITY)

        view = STUDENT_VIEW
        if request.user.is_anonymous:
            view = PUBLIC_VIEW

        context = {'specific_masquerade': is_masquerading_as_specific_student(request.user, usage_key.course_key)}
        return Response(sequence.get_metadata(view=view, context=context))
Exemplo n.º 7
0
    def __init__(self, course_key, request, username=''):
        self.request = request
        self.overview = course_detail(
            self.request,
            username or self.request.user.username,
            course_key,
        )

        self.original_user_is_staff = has_access(self.request.user, 'staff',
                                                 self.overview).has_access
        self.original_user_is_global_staff = self.request.user.is_staff
        self.course_key = course_key
        self.course = get_course_by_id(self.course_key)
        self.course_masquerade, self.effective_user = setup_masquerade(
            self.request,
            course_key,
            staff_access=self.original_user_is_staff,
        )
        self.request.user = self.effective_user
        self.is_staff = has_access(self.effective_user, 'staff',
                                   self.overview).has_access
        self.enrollment_object = CourseEnrollment.get_enrollment(
            self.effective_user,
            self.course_key,
            select_related=['celebration', 'user__celebration'])
        self.can_view_legacy_courseware = courseware_legacy_is_visible(
            course_key=course_key,
            is_global_staff=self.original_user_is_global_staff,
        )
Exemplo n.º 8
0
def reset_course_deadlines(request):
    """
    Set the start_date of a schedule to today, which in turn will adjust due dates for
    sequentials belonging to a self paced course
    """
    from lms.urls import RENDER_XBLOCK_NAME
    from openedx.features.course_experience.urls import COURSE_HOME_VIEW_NAME

    detail_id_dict = ast.literal_eval(
        request.POST.get('reset_deadlines_redirect_url_id_dict'))
    redirect_url = request.POST.get('reset_deadlines_redirect_url_base',
                                    COURSE_HOME_VIEW_NAME)
    course_key = CourseKey.from_string(detail_id_dict['course_id'])
    masquerade_details, masquerade_user = setup_masquerade(
        request, course_key, has_access(request.user, 'staff', course_key))
    if masquerade_details and masquerade_details.role == 'student' and masquerade_details.user_name and (
            redirect_url == COURSE_HOME_VIEW_NAME):
        # Masquerading as a specific student, so reset that student's schedule
        user = masquerade_user
    else:
        user = request.user
    reset_self_paced_schedule(user, course_key)
    if redirect_url == RENDER_XBLOCK_NAME:
        detail_id_dict.pop('course_id')
    return redirect(reverse(redirect_url, kwargs=detail_id_dict))
Exemplo n.º 9
0
    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_staff = has_access(request.user, 'staff', course_key).has_access

        _, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        course = course_detail(request, request.user.username, course_key)
        user_is_enrolled = CourseEnrollment.is_enrolled(request.user, course_key_string)

        data = {
            'course_id': course.id,
            'is_staff': has_access(request.user, 'staff', course_key).has_access,
            'original_user_is_staff': original_user_is_staff,
            'number': course.display_number_with_default,
            'org': course.display_org_with_default,
            'tabs': get_course_tab_list(request.user, course),
            'title': course.display_name_with_default,
            'is_self_paced': getattr(course, 'self_paced', False),
            'is_enrolled': user_is_enrolled,
        }
        context = self.get_serializer_context()
        context['course'] = course
        serializer = self.get_serializer_class()(data, context=context)
        return Response(serializer.data)
Exemplo n.º 10
0
    def post(self, request, course_key_string, *args, **kwargs):  # lint-amnesty, pylint: disable=unused-argument
        """
        Handle a POST request.
        """
        course_key = CourseKey.from_string(course_key_string)

        # Check if we're masquerading as someone else. If so, we should just ignore this request.
        _, user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )
        if user != request.user:
            return Response(status=202)  # "Accepted"

        data = dict(request.data)
        first_section = data.pop('first_section', None)
        if data:
            return Response(status=400)  # there were parameters we didn't recognize

        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        if not enrollment:
            return Response(status=404)

        defaults = {}
        if first_section is not None:
            defaults['celebrate_first_section'] = first_section

        if defaults:
            _, created = CourseEnrollmentCelebration.objects.update_or_create(enrollment=enrollment, defaults=defaults)
            return Response(status=201 if created else 200)
        else:
            return Response(status=200)  # just silently allow it
Exemplo n.º 11
0
    def get(self, request, usage_key_string, *args, **kwargs):  # lint-amnesty, pylint: disable=unused-argument
        """
        Return response to a GET request.
        """
        try:
            usage_key = UsageKey.from_string(usage_key_string)
        except InvalidKeyError:
            raise NotFound("Invalid usage key: '{}'.".format(usage_key_string))  # lint-amnesty, pylint: disable=raise-missing-from

        _, request.user = setup_masquerade(
            request,
            usage_key.course_key,
            staff_access=has_access(request.user, 'staff',
                                    usage_key.course_key),
            reset_masquerade_data=True,
        )

        sequence, _ = get_module_by_usage_id(self.request,
                                             str(usage_key.course_key),
                                             str(usage_key),
                                             disable_staff_debug_info=True,
                                             will_recheck_access=True)

        view = STUDENT_VIEW
        if request.user.is_anonymous:
            view = PUBLIC_VIEW

        return Response(
            json.loads(sequence.handle_ajax('metadata', None, view=view)))
Exemplo n.º 12
0
    def _get_student_user(self, request, course_key, student_id, is_staff):
        """Gets the student User object, either from coaching, masquerading, or normal actual request"""
        if student_id:
            try:
                student_id = int(student_id)
            except ValueError as e:
                raise Http404 from e

        if student_id is None or student_id == request.user.id:
            _, student = setup_masquerade(
                request,
                course_key,
                staff_access=is_staff,
                reset_masquerade_data=True
            )
            return student

        # When a student_id is passed in, we display the progress page for the user
        # with the provided user id, rather than the requesting user
        try:
            coach_access = has_ccx_coach_role(request.user, course_key)
        except CCXLocatorValidationException:
            coach_access = False

        has_access_on_students_profiles = is_staff or coach_access
        # Requesting access to a different student's profile
        if not has_access_on_students_profiles:
            raise Http404

        try:
            return User.objects.get(id=student_id)
        except User.DoesNotExist as exc:
            raise Http404 from exc
Exemplo n.º 13
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        _, request.user = setup_masquerade(request,
                                           course_key,
                                           staff_access=has_access(
                                               request.user, 'staff',
                                               course_key),
                                           reset_masquerade_data=True)

        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        transformers = BlockStructureTransformers()
        transformers += course_blocks_api.get_course_block_access_transformers(
            request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        course_blocks = get_course_blocks(request.user,
                                          course_usage_key,
                                          transformers,
                                          include_completion=True)

        enrollment_mode, _ = CourseEnrollment.enrollment_mode_for_user(
            request.user, course_key)

        course_grade = CourseGradeFactory().read(request.user, course)
        courseware_summary = course_grade.chapter_grades.values()

        data = {
            'course_blocks': course_blocks,
            'courseware_summary': courseware_summary,
            'enrollment_mode': enrollment_mode,
            'user_timezone': user_timezone,
        }
        context = self.get_serializer_context()
        context['staff_access'] = bool(
            has_access(request.user, 'staff', course))
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Exemplo n.º 14
0
def reset_course_deadlines(request):
    """
    Set the start_date of a schedule to today, which in turn will adjust due dates for
    sequentials belonging to a self paced course

    IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines`
    function in common/djangoapps/util/views.py as well.
    """
    course_key = request.data.get('course_key', None)

    # If body doesnt contain 'course_key', return 400 to client.
    if not course_key:
        raise ParseError(_("'course_key' is required."))

    # If body contains params other than 'course_key', return 400 to client.
    if len(request.data) > 1:
        raise ParseError(_("Only 'course_key' is expected."))

    try:
        course_key = CourseKey.from_string(course_key)
        _course_masquerade, user = setup_masquerade(
            request, course_key, has_access(request.user, 'staff', course_key))

        missed_deadlines, missed_gated_content = dates_banner_should_display(
            course_key, user)
        if missed_deadlines and not missed_gated_content:
            reset_self_paced_schedule(user, course_key)

        if course_home_mfe_dates_tab_is_active(course_key):
            body_link = get_microfrontend_url(course_key=str(course_key),
                                              view_name='dates')
        else:
            body_link = '{}{}'.format(settings.LMS_ROOT_URL,
                                      reverse('dates', args=[str(course_key)]))

        return Response({
            'body':
            format_html('<a href="{}">{}</a>', body_link, _('View all dates')),
            'header':
            _('Your due dates have been successfully shifted to help you stay on track.'
              ),
            'link':
            body_link,
            'link_text':
            _('View all dates'),
            'message':
            _('Deadlines successfully reset.'),
        })
    except Exception as e:
        log.exception(e)
        raise UnableToResetDeadlines
Exemplo n.º 15
0
def _get_context(request, course_id):
    """
        Return all course/student/user data
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    # Get general info of course
    grade_cutoff, avg_grade, min_grade, max_grade = _get_course_info(
        course, course_key)

    # masquerade and student required for preview_menu (admin)
    staff_access = bool(has_access(request.user, 'staff', course))
    masquerade, student = setup_masquerade(request,
                                           course_key,
                                           staff_access,
                                           reset_masquerade_data=True)
    prefetch_related_objects([student], 'groups')
    if request.user.id != student.id:
        # refetch the course as the assumed student
        course = get_course_with_access(student,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
    course_grade = CourseGradeFactory().read(student, course)  # Student grades
    courseware_summary = list(course_grade.chapter_grades.values())
    course_expiration_fragment = generate_course_expired_fragment(
        student, course)

    context = {
        "course": course,
        "avg_grade": avg_grade,
        "min_grade": min_grade,
        "max_grade": max_grade,
        "grade_cutoff": grade_cutoff,
        "supports_preview_menu": True,
        "staff_access": staff_access,
        "masquerade": masquerade,
        "can_masquerade": staff_access,
        "student": student,
        "courseware_summary": courseware_summary,
        "grade_summary": course_grade.summary,
        "course_expiration_fragment": course_expiration_fragment,
        "grade_percent_scaled": grade_percent_scaled,
        "get_section_visibility": get_section_visibility,
        "get_feedback": get_feedback,
        "update_url": reverse('feedback_post_update'),
        "set_visibility_url": reverse('feedback_post_set_visibility'),
    }
    return context
Exemplo n.º 16
0
    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_staff = has_access(request.user, 'staff',
                                            course_key).has_access

        _, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        username = request.user.username if request.user.username else None
        course = course_detail(request, request.user.username, course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user,
                                                     course_key_string)
        user_is_enrolled = bool(enrollment and enrollment.is_active)

        courseware_meta = CoursewareMeta(course_key, request,
                                         request.user.username)
        can_load_courseware = courseware_meta.is_microfrontend_enabled_for_user(
        )

        browser_timezone = self.request.query_params.get(
            'browser_timezone', None)
        celebrations = get_celebrations_dict(request.user, enrollment, course,
                                             browser_timezone)

        data = {
            'course_id': course.id,
            'username': username,
            'is_staff': has_access(request.user, 'staff',
                                   course_key).has_access,
            'original_user_is_staff': original_user_is_staff,
            'number': course.display_number_with_default,
            'org': course.display_org_with_default,
            'tabs': get_course_tab_list(request.user, course),
            'title': course.display_name_with_default,
            'is_self_paced': getattr(course, 'self_paced', False),
            'is_enrolled': user_is_enrolled,
            'can_load_courseware': can_load_courseware,
            'celebrations': celebrations,
        }
        context = self.get_serializer_context()
        context['course'] = course
        context['course_overview'] = course
        context['enrollment'] = enrollment
        serializer = self.get_serializer_class()(data, context=context)
        return Response(serializer.data)
Exemplo n.º 17
0
def reset_course_deadlines(request):
    """
    Set the start_date of a schedule to today, which in turn will adjust due dates for
    sequentials belonging to a self paced course
    """
    course_key = CourseKey.from_string(request.POST.get('course_id'))
    _course_masquerade, user = setup_masquerade(
        request, course_key, has_access(request.user, 'staff', course_key))

    missed_deadlines, missed_gated_content = dates_banner_should_display(
        course_key, user)
    if missed_deadlines and not missed_gated_content:
        reset_self_paced_schedule(user, course_key)

    referrer = request.META.get('HTTP_REFERER')
    return redirect(referrer) if referrer else HttpResponse()
Exemplo n.º 18
0
def reset_course_deadlines(request, course_id):
    """
    Set the start_date of a schedule to today, which in turn will adjust due dates for
    sequentials belonging to a self paced course
    """
    course_key = CourseKey.from_string(course_id)
    masquerade_details, masquerade_user = setup_masquerade(
        request, course_key, has_access(request.user, 'staff', course_key))
    if masquerade_details and masquerade_details.role == 'student' and masquerade_details.user_name:
        # Masquerading as a specific student, so reset that student's schedule
        user = masquerade_user
    else:
        user = request.user
    reset_self_paced_schedule(user, course_key)
    return redirect(
        reverse('openedx.course_experience.course_home',
                args=[six.text_type(course_key)]))
Exemplo n.º 19
0
 def __init__(self, course_key, request, username=''):
     self.request = request
     self.overview = course_detail(
         self.request,
         username or self.request.user.username,
         course_key,
     )
     self.original_user_is_staff = has_access(self.request.user, 'staff', self.overview).has_access
     self.course_key = course_key
     self.course_masquerade, self.effective_user = setup_masquerade(
         self.request,
         course_key,
         staff_access=self.original_user_is_staff,
     )
     self.request.user = self.effective_user
     self.is_staff = has_access(self.effective_user, 'staff', self.overview).has_access
     self.enrollment_object = CourseEnrollment.get_enrollment(self.effective_user, self.course_key,
                                                              select_related=['celebration'])
Exemplo n.º 20
0
def reset_course_deadlines(request):
    """
    Set the start_date of a schedule to today, which in turn will adjust due dates for
    sequentials belonging to a self paced course

    IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines`
    function in openedx/features/course_experience/api/v1/views.py as well.
    """
    course_key = CourseKey.from_string(request.POST.get('course_id'))
    _course_masquerade, user = setup_masquerade(
        request, course_key, has_access(request.user, 'staff', course_key))

    missed_deadlines, missed_gated_content = dates_banner_should_display(
        course_key, user)
    if missed_deadlines and not missed_gated_content:
        reset_self_paced_schedule(user, course_key)

    referrer = request.META.get('HTTP_REFERER')
    return redirect(referrer) if referrer else HttpResponse()
Exemplo n.º 21
0
    def test_setup_masquerade(self):
        masquerade_settings = {
            self.course.id:
            CourseMasquerade(course_key=self.course.id,
                             role='student',
                             user_name=self.student.username)
        }
        self.request.session[MASQUERADE_SETTINGS_KEY] = masquerade_settings

        course_masquerade, masquerade_user = setup_masquerade(
            self.request, self.course.id, staff_access=True)

        # Warning: the SafeSessions middleware relies on the `real_user` attribute to see if a
        # user is masquerading as another user.  If the name of this attribute is changing, please update
        # the check in SafeSessionMiddleware._verify_user_unchanged as well.
        assert masquerade_user.real_user == self.staff
        assert masquerade_user == self.student
        assert self.request.user.masquerade_settings == masquerade_settings
        assert course_masquerade == masquerade_settings[self.course.id]
Exemplo n.º 22
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        _, request.user = setup_masquerade(request,
                                           course_key,
                                           staff_access=has_access(
                                               request.user, 'staff',
                                               course_key),
                                           reset_masquerade_data=True)

        transformers = BlockStructureTransformers()
        transformers += course_blocks_api.get_course_block_access_transformers(
            request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]
        get_course_with_access(request.user,
                               'load',
                               course_key,
                               check_if_enrolled=True)
        course_blocks = get_course_blocks(request.user,
                                          course_usage_key,
                                          transformers,
                                          include_completion=True)

        enrollment_mode, _ = CourseEnrollment.enrollment_mode_for_user(
            request.user, course_key)

        data = {
            'course_blocks': course_blocks,
            'enrollment_mode': enrollment_mode,
        }

        serializer = self.get_serializer(data)

        return Response(serializer.data)
Exemplo n.º 23
0
 def __init__(self, course_key, request, username=''):
     self.overview = course_detail(
         request,
         username or request.user.username,
         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
Exemplo n.º 24
0
def reset_course_deadlines(request):
    """
    Set the start_date of a schedule to today, which in turn will adjust due dates for
    sequentials belonging to a self paced course

    IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines`
    function in openedx/features/course_experience/api/v1/views.py as well.
    """
    course_key = CourseKey.from_string(request.POST.get('course_id'))
    _course_masquerade, user = setup_masquerade(
        request, course_key, has_access(request.user, 'staff', course_key))

    # We ignore the missed_deadlines because this endpoint could be used for
    # learners who have remaining attempts on a problem and reset their due dates in order to
    # submit additional attempts. This can apply for 'completed' (submitted) content that would
    # not be marked as past_due
    _missed_deadlines, missed_gated_content = dates_banner_should_display(
        course_key, user)
    if not missed_gated_content:
        reset_self_paced_schedule(user, course_key)

    referrer = request.META.get('HTTP_REFERER')
    return redirect(referrer) if referrer else HttpResponse()
Exemplo n.º 25
0
    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_staff = has_access(request.user, 'staff', course_key).has_access

        _, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        course = course_detail(request, request.user.username, course_key)
        user_is_enrolled = CourseEnrollment.is_enrolled(request.user, course_key_string)
        browser_timezone = request.query_params.get('browser_timezone', None)
        celebrations = {
            'streak_length_to_celebrate': UserCelebration.perform_streak_updates(
                request.user, course_key, browser_timezone
            )
        }
        data = {
            'course_id': course.id,
            'is_staff': has_access(request.user, 'staff', course_key).has_access,
            'original_user_is_staff': original_user_is_staff,
            'number': course.display_number_with_default,
            'org': course.display_org_with_default,
            'tabs': get_course_tab_list(request.user, course),
            'title': course.display_name_with_default,
            'is_self_paced': getattr(course, 'self_paced', False),
            'is_enrolled': user_is_enrolled,
            'celebrations': celebrations,
        }
        context = self.get_serializer_context()
        context['course'] = course
        serializer = self.get_serializer_class()(data, context=context)
        return Response(serializer.data)
Exemplo n.º 26
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        if not course_home_mfe_outline_tab_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        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)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        masquerade_object, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        user_is_masquerading = is_masquerading(
            request.user, course_key, course_masquerade=masquerade_object)

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(
            course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        allow_public_outline = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(
            reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_learning_mfe_home_url(course_key=course.id,
                                                       view_name='dates')

        # Set all of the defaults
        access_expiration = None
        course_blocks = None
        course_goals = {'goal_options': [], 'selected_goal': None}
        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)
        dates_widget = {
            'course_date_blocks': [],
            'dates_tab_link': dates_tab_link,
            'user_timezone': user_timezone,
        }
        enroll_alert = {
            'can_enroll': True,
            'extra_text': None,
        }
        handouts_html = None
        offer_data = None
        resume_course = {
            'has_visited_course': False,
            'url': None,
        }
        welcome_message_html = None

        is_enrolled = enrollment and enrollment.is_active
        is_staff = bool(has_access(request.user, 'staff', course_key))
        show_enrolled = is_enrolled or is_staff
        if show_enrolled:
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, request.user)
            date_blocks = get_course_date_blocks(course,
                                                 request.user,
                                                 request,
                                                 num_assignments=1)
            dates_widget['course_date_blocks'] = [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ]

            handouts_html = get_course_info_section(request, request.user,
                                                    course, 'handouts')
            welcome_message_html = get_current_update_for_user(request, course)

            offer_data = generate_offer_data(request.user, course_overview)
            access_expiration = get_access_expiration_data(
                request.user, course_overview)

            # Only show the set course goal message for enrolled, unverified
            # users in a course that allows for verified statuses.
            is_already_verified = CourseEnrollment.is_enrolled_as_verified(
                request.user, course_key)
            if not is_already_verified and has_course_goal_permission(
                    request, course_key_string, {'is_enrolled': is_enrolled}):
                course_goals = {
                    'goal_options':
                    valid_course_goals_ordered(include_unsure=True),
                    'selected_goal': None
                }

                selected_goal = get_course_goal(request.user, course_key)
                if selected_goal:
                    course_goals['selected_goal'] = {
                        'key': selected_goal.goal_key,
                        'text': get_course_goal_text(selected_goal.goal_key),
                    }

            try:
                resume_block = get_key_to_last_completed_block(
                    request.user, course.id)
                resume_course['has_visited_course'] = True
                resume_path = reverse('jump_to',
                                      kwargs={
                                          'course_id': course_key_string,
                                          'location': str(resume_block)
                                      })
                resume_course['url'] = request.build_absolute_uri(resume_path)
            except UnavailableCompletionData:
                start_block = get_start_block(course_blocks)
                resume_course['url'] = start_block['lms_web_url']

        elif allow_public_outline or allow_public or user_is_masquerading:
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, None)
            if allow_public or user_is_masquerading:
                handouts_html = get_course_info_section(
                    request, request.user, course, 'handouts')

        if not show_enrolled:
            if CourseMode.is_masters_only(course_key):
                enroll_alert['can_enroll'] = False
                enroll_alert['extra_text'] = _(
                    'Please contact your degree administrator or '
                    'edX Support if you have questions.')
            elif course.invitation_only:
                enroll_alert['can_enroll'] = False

        data = {
            'access_expiration': access_expiration,
            'course_blocks': course_blocks,
            'course_goals': course_goals,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'enroll_alert': enroll_alert,
            'handouts_html': handouts_html,
            'has_ended': course.has_ended(),
            'offer': offer_data,
            'resume_course': resume_course,
            'welcome_message_html': welcome_message_html,
        }
        context = self.get_serializer_context()
        context['course_overview'] = course_overview
        context['enable_links'] = show_enrolled or allow_public
        context['enrollment'] = enrollment
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Exemplo n.º 27
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        if not course_home_mfe_outline_tab_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        _masquerade, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(
            course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        is_enrolled = enrollment and enrollment.is_active
        is_staff = has_access(request.user, 'staff', course_key)
        show_enrolled = is_enrolled or is_staff

        show_handouts = show_enrolled or allow_public
        handouts_html = get_course_info_section(
            request, request.user, course, 'handouts') if show_handouts else ''

        # TODO: TNL-7185 Legacy: Refactor to return the offer & expired data and format the message in the MFE
        offer_html = generate_offer_html(request.user, course_overview)
        course_expired_html = generate_course_expired_message(
            request.user, course_overview)

        welcome_message_html = None
        if get_course_tag(request.user, course_key, PREFERENCE_KEY) != 'False':
            if LATEST_UPDATE_FLAG.is_enabled(course_key):
                welcome_message_html = LatestUpdateFragmentView(
                ).latest_update_html(request, course)
            else:
                welcome_message_html = WelcomeMessageFragmentView(
                ).welcome_message_html(request, course)

        enroll_alert = {
            'can_enroll': True,
            'extra_text': None,
        }
        if not show_enrolled:
            if CourseMode.is_masters_only(course_key):
                enroll_alert['can_enroll'] = False
                enroll_alert['extra_text'] = _(
                    'Please contact your degree administrator or '
                    'edX Support if you have questions.')
            elif course.invitation_only:
                enroll_alert['can_enroll'] = False

        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)
        date_blocks = get_course_date_blocks(course,
                                             request.user,
                                             request,
                                             num_assignments=1)

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(
            reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_microfrontend_url(course_key=course.id,
                                                   view_name='dates')

        transformers = BlockStructureTransformers()
        transformers += get_course_block_access_transformers(request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]

        course_blocks = get_course_blocks(request.user,
                                          course_usage_key,
                                          transformers,
                                          include_completion=True)

        dates_widget = {
            'course_date_blocks': [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ],
            'dates_tab_link':
            dates_tab_link,
            'user_timezone':
            user_timezone,
        }

        data = {
            'course_blocks': course_blocks,
            'course_expired_html': course_expired_html,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'enroll_alert': enroll_alert,
            'handouts_html': handouts_html,
            'offer_html': offer_html,
            'welcome_message_html': welcome_message_html,
        }
        context = self.get_serializer_context()
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Exemplo n.º 28
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        if not course_home_mfe_outline_tab_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        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)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        _masquerade, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(
            course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        allow_public_outline = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE
        is_enrolled = enrollment and enrollment.is_active
        is_staff = bool(has_access(request.user, 'staff', course_key))
        show_enrolled = is_enrolled or is_staff

        show_handouts = show_enrolled or allow_public
        handouts_html = get_course_info_section(
            request, request.user, course, 'handouts') if show_handouts else ''

        # TODO: TNL-7185 Legacy: Refactor to return the offer & expired data and format the message in the MFE
        offer_html = show_enrolled and generate_offer_html(
            request.user, course_overview)
        course_expired_html = show_enrolled and generate_course_expired_message(
            request.user, course_overview)

        welcome_message_html = None
        if show_enrolled:
            if LATEST_UPDATE_FLAG.is_enabled(course_key):
                welcome_message_html = LatestUpdateFragmentView(
                ).latest_update_html(request, course)
            elif get_course_tag(request.user, course_key,
                                PREFERENCE_KEY) != 'False':
                welcome_message_html = WelcomeMessageFragmentView(
                ).welcome_message_html(request, course)

        enroll_alert = {
            'can_enroll': True,
            'extra_text': None,
        }
        if not show_enrolled:
            if CourseMode.is_masters_only(course_key):
                enroll_alert['can_enroll'] = False
                enroll_alert['extra_text'] = _(
                    'Please contact your degree administrator or '
                    'edX Support if you have questions.')
            elif course.invitation_only:
                enroll_alert['can_enroll'] = False

        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)
        date_blocks = get_course_date_blocks(course,
                                             request.user,
                                             request,
                                             num_assignments=1)

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(
            reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_microfrontend_url(course_key=course.id,
                                                   view_name='dates')

        course_blocks = None
        if show_enrolled or allow_public or allow_public_outline:
            outline_user = request.user if show_enrolled else None
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, outline_user)

        resume_course = {
            'has_visited_course': False,
            'url': None,
        }
        if show_enrolled:
            try:
                resume_block = get_key_to_last_completed_block(
                    request.user, course.id)
                resume_course['has_visited_course'] = True
            except UnavailableCompletionData:
                resume_block = course_usage_key
            resume_path = reverse('jump_to',
                                  kwargs={
                                      'course_id': course_key_string,
                                      'location': str(resume_block)
                                  })
            resume_course['url'] = request.build_absolute_uri(resume_path)

        dates_widget = {
            'course_date_blocks': [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ],
            'dates_tab_link':
            dates_tab_link,
            'user_timezone':
            user_timezone,
        }

        # Only show the set course goal message for enrolled, unverified
        # users in a course that allows for verified statuses.
        is_already_verified = CourseEnrollment.is_enrolled_as_verified(
            request.user, course_key)
        if (not is_already_verified and has_course_goal_permission(
                request, course_key_string, {'is_enrolled': is_enrolled})):
            course_goals = {
                'goal_options':
                valid_course_goals_ordered(include_unsure=True),
                'selected_goal': None
            }

            selected_goal = get_course_goal(request.user, course_key)
            if selected_goal:
                course_goals['selected_goal'] = {
                    'key': selected_goal.goal_key,
                    'text': get_course_goal_text(selected_goal.goal_key),
                }
        else:
            course_goals = {'goal_options': [], 'selected_goal': None}

        data = {
            'course_blocks': course_blocks,
            'course_expired_html': course_expired_html or None,
            'course_goals': course_goals,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'enroll_alert': enroll_alert,
            'handouts_html': handouts_html or None,
            'has_ended': course.has_ended(),
            'offer_html': offer_html or None,
            'resume_course': resume_course,
            'welcome_message_html': welcome_message_html or None,
        }
        context = self.get_serializer_context()
        context['course_key'] = course_key
        context['enable_links'] = show_enrolled or allow_public
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Exemplo n.º 29
0
def reset_course_deadlines(request):
    """
    Set the start_date of a schedule to today, which in turn will adjust due dates for
    sequentials belonging to a self paced course

    Request Parameters:
        course_key: course key
        research_event_data: any data that should be included in the research tracking event
            Example: sending the location of where the reset deadlines banner (i.e. outline-tab)

    IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines`
    function in common/djangoapps/util/views.py as well.
    """
    course_key = request.data.get('course_key', None)
    research_event_data = request.data.get('research_event_data', {})

    # If body doesnt contain 'course_key', return 400 to client.
    if not course_key:
        raise ParseError(_("'course_key' is required."))

    try:
        course_key = CourseKey.from_string(course_key)
        course_masquerade, user = setup_masquerade(
            request, course_key, has_access(request.user, 'staff', course_key))

        # We ignore the missed_deadlines because this endpoint is used in the Learning MFE for
        # learners who have remaining attempts on a problem and reset their due dates in order to
        # submit additional attempts. This can apply for 'completed' (submitted) content that would
        # not be marked as past_due
        _missed_deadlines, missed_gated_content = dates_banner_should_display(
            course_key, user)
        if not missed_gated_content:
            reset_self_paced_schedule(user, course_key)

            course_overview = course_detail(request, user.username, course_key)
            # For context here, research_event_data should already contain `location` indicating
            # the page/location dates were reset from and could also contain `block_id` if reset
            # within courseware.
            research_event_data.update({
                'courserun_key':
                str(course_key),
                'is_masquerading':
                is_masquerading(user, course_key, course_masquerade),
                'is_staff':
                has_access(user, 'staff', course_key).has_access,
                'org_key':
                course_overview.display_org_with_default,
                'user_id':
                user.id,
            })
            tracker.emit('edx.ui.lms.reset_deadlines.clicked',
                         research_event_data)

        if course_home_legacy_is_active(course_key):
            body_link = '{}{}'.format(settings.LMS_ROOT_URL,
                                      reverse('dates', args=[str(course_key)]))
        else:
            body_link = get_learning_mfe_home_url(course_key=str(course_key),
                                                  view_name='dates')

        return Response({
            'body':
            format_html('<a href="{}">{}</a>', body_link, _('View all dates')),
            'header':
            _('Your due dates have been successfully shifted to help you stay on track.'
              ),
            'link':
            body_link,
            'link_text':
            _('View all dates'),
            'message':
            _('Deadlines successfully reset.'),
        })
    except Exception as reset_deadlines_exception:
        log.exception('Error occurred while trying to reset deadlines!')
        raise UnableToResetDeadlines from reset_deadlines_exception
Exemplo n.º 30
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)

        if not course_home_mfe_dates_tab_is_active(course_key):
            return Response(status=status.HTTP_404_NOT_FOUND)

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        _, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        blocks = get_course_date_blocks(course,
                                        request.user,
                                        request,
                                        include_access=True,
                                        include_past_dates=True)
        missed_deadlines, missed_gated_content = dates_banner_should_display(
            course_key, request.user)

        learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment(
            user=request.user,
            course_key=course_key,
        )

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        data = {
            'has_ended':
            course.has_ended(),
            'course_date_blocks':
            [block for block in blocks if not isinstance(block, TodaysDate)],
            'missed_deadlines':
            missed_deadlines,
            'missed_gated_content':
            missed_gated_content,
            'learner_is_full_access':
            learner_is_full_access,
            'user_timezone':
            user_timezone,
            'verified_upgrade_link':
            verified_upgrade_deadline_link(request.user, course=course),
        }
        context = self.get_serializer_context()
        context['learner_is_full_access'] = learner_is_full_access
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)