Beispiel #1
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Fragment to render the course reviews fragment.

        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_url_name = default_course_url_name(course.id)
        course_url = reverse(course_url_name,
                             kwargs={'course_id': six.text_type(course.id)})

        is_enrolled = CourseEnrollment.is_enrolled(request.user, course.id)

        # Create the fragment
        course_reviews_fragment = CourseReviewsModuleFragmentView(
        ).render_to_fragment(request, course=course, **kwargs)

        context = {
            'course': course,
            'course_url': course_url,
            'course_reviews_fragment': course_reviews_fragment,
            'is_enrolled': is_enrolled,
        }

        html = render_to_string(
            'course_experience/course-reviews-fragment.html', context)
        return Fragment(html)
Beispiel #2
0
    def _get_course(self, course_key_string, user, access_action):
        """
        Returns the course for the given course_key_string after
        verifying the requested access to the course by the given user.
        """
        try:
            course_key = CourseKey.from_string(course_key_string)
        except InvalidKeyError:
            return self.make_error_response(
                status_code=status.HTTP_404_NOT_FOUND,
                developer_message='The provided course key cannot be parsed.',
                error_code='invalid_course_key'
            )

        try:
            return courses.get_course_with_access(
                user,
                access_action,
                course_key,
                check_if_enrolled=True,
            )
        except Http404:
            log.info('Course with ID "%s" not found', course_key_string)
        except CourseAccessRedirect:
            log.info('User %s does not have access to course with ID "%s"', user.username, course_key_string)
        return self.make_error_response(
            status_code=status.HTTP_404_NOT_FOUND,
            developer_message='The user, the course or both do not exist.',
            error_code='user_or_course_does_not_exist',
        )
Beispiel #3
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Renders the course's home page as a fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        course_url_name = default_course_url_name(course.id)
        course_url = reverse(course_url_name,
                             kwargs={'course_id': six.text_type(course.id)})

        ordered_updates = get_ordered_updates(request, course)
        plain_html_updates = ''
        if ordered_updates:
            plain_html_updates = self.get_plain_html_updates(request, course)

        # Render the course home fragment
        context = {
            'csrf': csrf(request)['csrf_token'],
            'course': course,
            'course_url': course_url,
            'updates': ordered_updates,
            'plain_html_updates': plain_html_updates,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
        }
        html = render_to_string(
            'course_experience/course-updates-fragment.html', context)
        return Fragment(html)
Beispiel #4
0
def edxnotes_visibility(request, course_id):
    """
    Handle ajax call from "Show notes" checkbox.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)
    field_data_cache = FieldDataCache([course], course_key, request.user)
    course_module = get_module_for_descriptor(request.user,
                                              request,
                                              course,
                                              field_data_cache,
                                              course_key,
                                              course=course)

    if not is_feature_enabled(course, request.user):
        raise Http404

    try:
        visibility = json.loads(request.body.decode('utf8'))["visibility"]
        course_module.edxnotes_visibility = visibility
        course_module.save()
        return JsonResponse(status=200)
    except (ValueError, KeyError):
        log.warning(
            u"Could not decode request body as JSON and find a boolean visibility field: '%s'",
            request.body)
        return JsonResponseBadRequest()
Beispiel #5
0
 def _wrapper(self, request, *args, **kwargs):
     """
     Expects kwargs to contain 'course_id'.
     Passes the course descriptor to the given decorated function.
     Raises 404 if access to course is disallowed.
     """
     course_id = CourseKey.from_string(kwargs.pop('course_id'))
     with modulestore().bulk_operations(course_id):
         try:
             course = get_course_with_access(
                 request.user,
                 'load_mobile',
                 course_id,
                 depth=depth,
                 check_if_enrolled=True,
             )
             # Record user activity for tracking progress towards a user's course goals (for mobile app)
             UserActivity.record_user_activity(
                 request.user, course_id, request=request, only_if_mobile_app=True
             )
         except CoursewareAccessException as error:
             return Response(data=error.to_json(), status=status.HTTP_404_NOT_FOUND)
         except CourseAccessRedirect as error:
             # If the redirect contains information about the triggering AccessError,
             # return the information contained in the AccessError.
             if error.access_error is not None:
                 return Response(data=error.access_error.to_json(), status=status.HTTP_404_NOT_FOUND)
             # Raise a 404 if the user does not have course access
             raise Http404  # lint-amnesty, pylint: disable=raise-missing-from
         return func(self, request, course=course, *args, **kwargs)
Beispiel #6
0
    def render_to_fragment(self, request, course_id, **kwargs):
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user, "load", course_key)

        staff_access = bool(has_access(request.user, 'staff', course))
        data_researcher_access = request.user.has_perm(permissions.CAN_RESEARCH, course_key)
        if not (staff_access or data_researcher_access):
            raise Http404()
        limit_student = LIMIT_STUDENTS
        if hasattr(settings, 'EOL_COMPLETION_LIMIT_STUDENT'):
            limit_student = settings.EOL_COMPLETION_LIMIT_STUDENT 
        is_big = limit_student < User.objects.filter(
            courseenrollment__course_id=course_key,
            courseenrollment__is_active=1,
            courseenrollment__mode='honor'
        ).count()
        if not is_big:
            context = self.get_context(request, course_id, course, course_key)
            html = render_to_string(
            'eol_completion/eol_completion_fragment.html', context)
        else:
            context = self.get_context_big_course(course, course_key)
            html = render_to_string(
                'eol_completion/eol_completion_bigcourse.html', context)
        fragment = Fragment(html)
        return fragment
Beispiel #7
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)
Beispiel #8
0
 def _wrapper(self, request, *args, **kwargs):
     """
     Expects kwargs to contain 'course_id'.
     Passes the course descriptor to the given decorated function.
     Raises 404 if access to course is disallowed.
     """
     course_id = CourseKey.from_string(kwargs.pop('course_id'))
     with modulestore().bulk_operations(course_id):
         try:
             course = get_course_with_access(request.user,
                                             access_action,
                                             course_id,
                                             depth=depth)
         except Http404:
             # any_unfulfilled_milestones called a second time since has_access returns a bool
             if check_for_milestones and any_unfulfilled_milestones(
                     course_id, request.user.id):
                 message = {
                     "developer_message":
                     "Cannot access content with unfulfilled "
                     "pre-requisites or unpassed entrance exam."
                 }
                 return response.Response(
                     data=message, status=status.HTTP_204_NO_CONTENT)
             else:
                 raise
         return func(self, request, course=course, *args, **kwargs)
Beispiel #9
0
def update_feedback(request):
    """
        Update or create feedback of block_id by POST Method. Request must have block_id, block_feedback and course_id params.
    """
    # check method and params
    if request.method != "POST":
        return HttpResponse(status=400)
    if 'block_id' not in request.POST or 'block_feedback' not in request.POST or 'course_id' not in request.POST:
        return HttpResponse(status=400)

    # check for access
    course_id = request.POST['course_id']
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)
    staff_access = bool(has_access(request.user, 'staff', course))
    if not staff_access:
        return HttpResponse(status=401)

    # get (and update) or create feedback
    block_id = request.POST['block_id']
    block_feedback = request.POST['block_feedback']
    try:
        feedback = EolFeedback.objects.get(block_id=block_id)
        feedback.block_feedback = block_feedback.strip()
        feedback.save()
        return HttpResponse(status=200)
    except EolFeedback.DoesNotExist:
        feedback = EolFeedback.objects.create(
            block_id=block_id, block_feedback=block_feedback.strip())
        return HttpResponse(status=201)
Beispiel #10
0
def set_visibility(request):
    """
        Update or create visibility of section_id by POST Method. Request must have section_id and course_id
    """
    # check method and params
    if request.method != "POST":
        return HttpResponse(status=400)
    if 'section_id' not in request.POST or 'course_id' not in request.POST:
        return HttpResponse(status=400)

    # check for access
    course_id = request.POST['course_id']
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)
    staff_access = bool(has_access(request.user, 'staff', course))
    if not staff_access:
        return HttpResponse(status=401)

    # change or create visibility
    section_id = request.POST['section_id']
    try:
        visibility = SectionVisibility.objects.get(section_id=section_id,
                                                   course_id=course_id)
        visibility.is_visible = not visibility.is_visible  # change bool
        visibility.save()
        return HttpResponse(status=200)
    except SectionVisibility.DoesNotExist:
        visibility = SectionVisibility.objects.create(section_id=section_id,
                                                      course_id=course_id,
                                                      is_visible=True)
        return HttpResponse(status=201)
Beispiel #11
0
def _create_base_discussion_view_context(request, course_key):
    """
    Returns the default template context for rendering any discussion view.
    """
    user = request.user
    cc_user = cc.User.from_django_user(user)
    user_info = cc_user.to_dict()
    course = get_course_with_access(user, 'load', course_key, check_if_enrolled=True)
    course_settings = make_course_settings(course, user)
    return {
        'csrf': csrf(request)['csrf_token'],
        'course': course,
        'user': user,
        'user_info': user_info,
        'staff_access': bool(has_access(user, 'staff', course)),
        'roles': utils.get_role_ids(course_key),
        'can_create_comment': has_permission(user, "create_comment", course.id),
        'can_create_subcomment': has_permission(user, "create_sub_comment", course.id),
        'can_create_thread': has_permission(user, "create_thread", course.id),
        'flag_moderator': bool(
            has_permission(user, 'openclose_thread', course.id) or
            has_access(user, 'staff', course)
        ),
        'course_settings': course_settings,
        'disable_courseware_js': True,
        'uses_bootstrap': True,
    }
Beispiel #12
0
 def _wrapper(self, request, *args, **kwargs):
     """
     Expects kwargs to contain 'course_id'.
     Passes the course descriptor to the given decorated function.
     Raises 404 if access to course is disallowed.
     """
     course_id = CourseKey.from_string(kwargs.pop('course_id'))
     with modulestore().bulk_operations(course_id):
         try:
             course = get_course_with_access(
                 request.user,
                 access_action,
                 course_id,
                 depth=depth
             )
         except Http404:
             # any_unfulfilled_milestones called a second time since has_access returns a bool
             if check_for_milestones and any_unfulfilled_milestones(course_id, request.user.id):
                 message = {
                     "developer_message": "Cannot access content with unfulfilled "
                                          "pre-requisites or unpassed entrance exam."
                 }
                 return response.Response(data=message, status=status.HTTP_204_NO_CONTENT)
             else:
                 raise
         return func(self, request, course=course, *args, **kwargs)
Beispiel #13
0
    def render_to_fragment(self, request, course_id=None, **kwargs):  # lint-amnesty, pylint: disable=arguments-differ
        """
        Renders the course's home page as a fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        course_url = default_course_url(course.id)

        ordered_updates = get_ordered_updates(request, course)
        plain_html_updates = ''
        if ordered_updates:
            plain_html_updates = self.get_plain_html_updates(request, course)

        # Render the course home fragment
        context = {
            'csrf': csrf(request)['csrf_token'],
            'course': course,
            'course_url': course_url,
            'updates': ordered_updates,
            'plain_html_updates': plain_html_updates,
            'disable_courseware_js': True,
        }
        html = render_to_string(
            'course_experience/course-updates-fragment.html', context)
        return Fragment(html)
Beispiel #14
0
    def process_view(self, request, view_func, view_args, view_kwargs):  # pylint: disable=unused-argument
        """
        This function handles authentication logic for wiki urls and redirects from
        the "root wiki" to the "course wiki" if the user accesses the wiki from a course url
        """
        # we care only about requests to wiki urls
        if not view_func.__module__.startswith('wiki.'):
            return

        # wiki pages are login required
        if not request.user.is_authenticated:
            return redirect(reverse('signin_user'), next=request.path)

        course_id = course_id_from_url(request.path)
        wiki_path = request.path.partition('/wiki/')[2]

        if course_id:
            # This is a /courses/org/name/run/wiki request
            course_path = "/courses/{}".format(text_type(course_id))
            # HACK: django-wiki monkeypatches the reverse function to enable
            # urls to be rewritten
            reverse._transform_url = lambda url: course_path + url  # pylint: disable=protected-access
            # Authorization Check
            # Let's see if user is enrolled or the course allows for public access
            try:
                course = get_course_with_access(request.user, 'load',
                                                course_id)
            except Http404:
                # course does not exist. redirect to root wiki.
                # clearing the referrer will cause process_response not to redirect
                # back to a non-existent course
                request.META['HTTP_REFERER'] = ''
                return redirect('/wiki/{}'.format(wiki_path))

            if not course.allow_public_wiki_access:
                is_enrolled = CourseEnrollment.is_enrolled(
                    request.user, course.id)
                is_staff = has_access(request.user, 'staff', course)
                if not (is_enrolled or is_staff):
                    # if a user is logged in, but not authorized to see a page,
                    # we'll redirect them to the course about page
                    return redirect('about_course', text_type(course_id))

                # If we need enterprise data sharing consent for this course, then redirect to the form.
                consent_url = get_enterprise_consent_url(
                    request, text_type(course_id))
                if consent_url:
                    return redirect(consent_url)

            # set the course onto here so that the wiki template can show the course navigation
            request.course = course
        else:
            # this is a request for /wiki/...

            # Check to see if we don't allow top-level access to the wiki via the /wiki/xxxx/yyy/zzz URLs
            # this will help prevent people from writing pell-mell to the Wiki in an unstructured way
            if not settings.FEATURES.get('ALLOW_WIKI_ROOT_ACCESS', False):
                raise PermissionDenied()

            return self._redirect_from_referrer(request, wiki_path)
Beispiel #15
0
    def render_to_fragment(self, request, course_id=None, **kwargs):  # lint-amnesty, pylint: disable=arguments-differ
        """
        Renders the welcome message fragment for the specified course.

        Returns: A fragment, or None if there is no welcome message.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        welcome_message_html = self.welcome_message_html(request, course)
        if not welcome_message_html:
            return None

        dismiss_url = reverse(
            'openedx.course_experience.dismiss_welcome_message',
            kwargs={'course_id': str(course_key)})

        context = {
            'dismiss_url': dismiss_url,
            'welcome_message_html': welcome_message_html,
        }

        html = render_to_string(
            'course_experience/welcome-message-fragment.html', context)
        return Fragment(html)
Beispiel #16
0
def course_detail(request, username, course_key):
    """
    Return a single course identified by `course_key`.

    The course must be visible to the user identified by `username` and the
    logged-in user should have permission to view courses available to that
    user.

    Arguments:
        request (HTTPRequest):
            Used to identify the logged-in user and to instantiate the course
            module to retrieve the course about description
        username (string):
            The name of the user `requesting_user would like to be identified as.
        course_key (CourseKey): Identifies the course of interest

    Return value:
        `CourseDescriptor` object representing the requested course
    """
    user = get_effective_user(request.user, username)
    try:
        course = get_course_with_access(user, 'see_exists', course_key)
    except Http404:
        raise NotFound()
    return course
Beispiel #17
0
def spoc_gradebook(request, course_id):
    """
    Show the gradebook for this course:
    - Only shown for courses with enrollment < settings.FEATURES.get("MAX_ENROLLMENT_INSTR_BUTTONS")
    - Only displayed to course staff
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user,
                                    'staff',
                                    course_key,
                                    depth=None)
    student_info, page = get_grade_book_page(request, course, course_key)

    return render_to_response(
        'courseware/gradebook.html',
        {
            'page':
            page,
            'page_url':
            reverse('spoc_gradebook',
                    kwargs={'course_id': six.text_type(course_key)}),
            'students':
            student_info,
            'course':
            course,
            'course_id':
            course_key,
            # Checked above
            'staff_access':
            True,
            'ordered_grades':
            sorted(list(course.grade_cutoffs.items()),
                   key=lambda i: i[1],
                   reverse=True),
        })
Beispiel #18
0
    def render_to_fragment(self, request, course_id=None, **kwargs):  # lint-amnesty, pylint: disable=arguments-differ
        """
        Renders the user's course bookmarks as a fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)

        language = UserPreference.get_value(request.user,
                                            'pref-lang',
                                            default='en')

        context = {
            'csrf': csrf(request)['csrf_token'],
            'course': course,
            'bookmarks_api_url': reverse('bookmarks'),
            'language_preference': language,
        }
        html = render_to_string(
            'course_bookmarks/course-bookmarks-fragment.html', context)
        inline_js = render_to_string(
            'course_bookmarks/course_bookmarks_js.template', context)
        fragment = Fragment(html)
        self.add_fragment_resource_urls(fragment)
        fragment.add_javascript(inline_js)
        return fragment
Beispiel #19
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Render the course dates fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=2)

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ]
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
Beispiel #20
0
 def _wrapper(self, request, *args, **kwargs):
     """
     Expects kwargs to contain 'course_id'.
     Passes the course descriptor to the given decorated function.
     Raises 404 if access to course is disallowed.
     """
     course_id = CourseKey.from_string(kwargs.pop('course_id'))
     with modulestore().bulk_operations(course_id):
         try:
             course = get_course_with_access(
                 request.user,
                 'load_mobile',
                 course_id,
                 depth=depth,
                 check_if_enrolled=True,
             )
         except CoursewareAccessException as error:
             return Response(data=error.to_json(), status=status.HTTP_404_NOT_FOUND)
         except CourseAccessRedirect as error:
             # If the redirect contains information about the triggering AccessError,
             # return the information contained in the AccessError.
             if error.access_error is not None:
                 return Response(data=error.access_error.to_json(), status=status.HTTP_404_NOT_FOUND)
             # Raise a 404 if the user does not have course access
             raise Http404
         return func(self, request, course=course, *args, **kwargs)
Beispiel #21
0
    def _get_course(self, course_key_string, user, access_action):
        """
        Returns the course for the given course_key_string after
        verifying the requested access to the course by the given user.
        """
        try:
            course_key = CourseKey.from_string(course_key_string)
        except InvalidKeyError:
            return self.make_error_response(
                status_code=status.HTTP_404_NOT_FOUND,
                developer_message='The provided course key cannot be parsed.',
                error_code='invalid_course_key'
            )

        try:
            return courses.get_course_with_access(
                user,
                access_action,
                course_key,
                check_if_enrolled=True,
            )
        except Http404:
            log.info('Course with ID "%s" not found', course_key_string)
        except CourseAccessRedirect:
            log.info('User %s does not have access to course with ID "%s"', user.username, course_key_string)
        return self.make_error_response(
            status_code=status.HTTP_404_NOT_FOUND,
            developer_message='The user, the course or both do not exist.',
            error_code='user_or_course_does_not_exist',
        )
Beispiel #22
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Render the course dates fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=1)
        # We will use this boolean to gate if we show a link to the dates tab. This same logic
        # dictates if we show the tab at all.
        user_enrolled = (
            request.user and request.user.is_authenticated and (bool(
                CourseEnrollment.is_enrolled(request.user, course.id)
                or has_access(request.user, 'staff', course, course.id))))

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ],
            'dates_tab_link':
            reverse('dates', args=[course.id]),
            'user_enrolled':
            user_enrolled,
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
Beispiel #23
0
 def test_get_course_info(self):
     course_key = self.course.id
     course = get_course_with_access(self.student, "load", course_key)
     grade_cutoff, avg_grade, min_grade, max_grade = views._get_course_info(
         course, course_key)
     self.assertEqual(grade_cutoff, 0.5)
     self.assertEqual(max_grade, 1.1)
Beispiel #24
0
    def render_to_fragment(self, request, course_id=None, **kwargs):  # lint-amnesty, pylint: disable=arguments-differ
        """
        Render the course dates fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=1)

        dates_tab_enabled = DatesTab.is_enabled(course, request.user)
        dates_tab_link = get_learning_mfe_home_url(course_key=course.id,
                                                   url_fragment='dates')

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ],
            'dates_tab_link':
            dates_tab_link,
            'dates_tab_enabled':
            dates_tab_enabled,
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
Beispiel #25
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Renders the welcome message fragment for the specified course.

        Returns: A fragment, or None if there is no welcome message.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
        welcome_message_html = self.welcome_message_html(request, course)
        if not welcome_message_html:
            return None

        dismiss_url = reverse(
            'openedx.course_experience.dismiss_welcome_message', kwargs={'course_id': six.text_type(course_key)}
        )

        context = {
            'dismiss_url': dismiss_url,
            'welcome_message_html': welcome_message_html,
            'shorten_welcome_message': SHORTEN_WELCOME_MESSAGE_FLAG.is_enabled(course_key),
        }

        if get_course_tag(request.user, course_key, PREFERENCE_KEY) == 'False':
            return None
        else:
            html = render_to_string('course_experience/welcome-message-fragment.html', context)
            return Fragment(html)
Beispiel #26
0
    def get(self, request, course_id):
        """
        Displays the user's bookmarks for the specified course.

        Arguments:
            request: HTTP request
            course_id (unicode): course id
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        course_url_name = default_course_url_name(course.id)
        course_url = reverse(course_url_name,
                             kwargs={'course_id': str(course.id)})

        # Render the bookmarks list as a fragment
        bookmarks_fragment = CourseBookmarksFragmentView().render_to_fragment(
            request, course_id=course_id)

        # Render the course bookmarks page
        context = {
            'csrf': csrf(request)['csrf_token'],
            'course': course,
            'supports_preview_menu': True,
            'course_url': course_url,
            'bookmarks_fragment': bookmarks_fragment,
            'disable_courseware_js': True,
            'uses_bootstrap': True,
        }
        return render_to_response('course_bookmarks/course-bookmarks.html',
                                  context)
Beispiel #27
0
def index(request, course_id, book_index, page=None):
    """
    Serve static image-based textbooks.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key)
    staff_access = bool(has_access(request.user, 'staff', course))

    book_index = int(book_index)
    if book_index < 0 or book_index >= len(course.textbooks):
        raise Http404(u"Invalid book index value: {0}".format(book_index))
    textbook = course.textbooks[book_index]
    table_of_contents = textbook.table_of_contents

    if page is None:
        page = textbook.start_page

    return render_to_response(
        'staticbook.html',
        {
            'book_index': book_index,
            'page': int(page),
            'course': course,
            'book_url': textbook.book_url,
            'table_of_contents': table_of_contents,
            'start_page': textbook.start_page,
            'end_page': textbook.end_page,
            'staff_access': staff_access,
        },
    )
Beispiel #28
0
def users_in_cohort(request, course_key_string, cohort_id):
    """
    Return users in the cohort.  Show up to 100 per page, and page
    using the 'page' GET attribute in the call.  Format:

    Returns:
        Json dump of dictionary in the following format:
        {'success': True,
         'page': page,
         'num_pages': paginator.num_pages,
         'users': [{'username': ..., 'email': ..., 'name': ...}]
    }
    """
    # this is a string when we get it here
    course_key = CourseKey.from_string(course_key_string)

    get_course_with_access(request.user, 'staff', course_key)

    # this will error if called with a non-int cohort_id.  That's ok--it
    # shouldn't happen for valid clients.
    cohort = cohorts.get_cohort_by_id(course_key, int(cohort_id))

    paginator = Paginator(cohort.users.all(), 100)
    try:
        page = int(request.GET.get('page'))
    except (TypeError, ValueError):
        # These strings aren't user-facing so don't translate them
        return HttpResponseBadRequest('Requested page must be numeric')
    else:
        if page < 0:
            return HttpResponseBadRequest('Requested page must be greater than zero')

    try:
        users = paginator.page(page)
    except EmptyPage:
        users = []  # When page > number of pages, return a blank page

    user_info = [{'username': u.username,
                  'email': u.email,
                  'name': u'{0} {1}'.format(u.first_name, u.last_name)}
                 for u in users]

    return json_http_response({'success': True,
                               'page': page,
                               'num_pages': paginator.num_pages,
                               'users': user_info})
Beispiel #29
0
def dismiss_welcome_message(request, course_id):
    """
    Given the course_id in the request, disable displaying the welcome message for the user.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
    dismiss_current_update_for_user(request, course)
    return HttpResponse()
Beispiel #30
0
def single_thread(request, course_key, discussion_id, thread_id):
    """
    Renders a response to display a single discussion thread.  This could either be a page refresh
    after navigating to a single thread, a direct link to a single thread, or an AJAX call from the
    discussions UI loading the responses/comments for a single thread.

    Depending on the HTTP headers, we'll adjust our response accordingly.
    """
    course = get_course_with_access(request.user,
                                    'load',
                                    course_key,
                                    check_if_enrolled=True)
    request.user.is_community_ta = utils.is_user_community_ta(
        request.user, course.id)

    if request.is_ajax():
        cc_user = cc.User.from_django_user(request.user)
        user_info = cc_user.to_dict()
        is_staff = has_permission(request.user, 'openclose_thread', course.id)

        try:
            _check_team_discussion_access(request, course, discussion_id)
        except TeamDiscussionHiddenFromUserException:
            return HttpResponseForbidden(TEAM_PERMISSION_MESSAGE)

        thread = _load_thread_for_viewing(
            request,
            course,
            discussion_id=discussion_id,
            thread_id=thread_id,
            raise_event=True,
        )

        with function_trace("get_annotated_content_infos"):
            annotated_content_info = utils.get_annotated_content_infos(
                course_key, thread, request.user, user_info=user_info)

        content = utils.prepare_content(thread.to_dict(), course_key, is_staff,
                                        request.user.is_community_ta)
        with function_trace("add_courseware_context"):
            add_courseware_context([content], course, request.user)

        return utils.JsonResponse({
            'content':
            content,
            'annotated_content_info':
            annotated_content_info,
        })
    else:
        course_id = str(course.id)
        tab_view = CourseTabView()
        return tab_view.get(request,
                            course_id,
                            'discussion',
                            discussion_id=discussion_id,
                            thread_id=thread_id)
Beispiel #31
0
 def clean_course_id(self):
     """Validate the 'course_id' value"""
     course_id = self.cleaned_data['course_id']
     try:
         course_key = CourseKey.from_string(course_id)
         self.cleaned_data['course'] = get_course_with_access(self.request_user, 'staff', course_key)
         self.cleaned_data['course_key'] = course_key
         return course_id
     except InvalidKeyError:
         raise ValidationError(u"'{}' is not a valid course key".format(text_type(course_id)))
Beispiel #32
0
 def clean_course_id(self):
     """Validate the 'course_id' value"""
     course_id = self.cleaned_data['course_id']
     try:
         course_key = CourseKey.from_string(course_id)
         self.cleaned_data['course'] = get_course_with_access(self.request_user, 'staff', course_key)
         self.cleaned_data['course_key'] = course_key
         return course_id
     except InvalidKeyError:
         raise ValidationError(f"'{str(course_id)}' is not a valid course key")  # lint-amnesty, pylint: disable=raise-missing-from
Beispiel #33
0
def cohorting_settings(request, course_key_string):
    """
    The handler for verified track cohorting requests.
    This will raise 404 if user is not staff.

    Returns a JSON representation of whether or not the course has verified track cohorting enabled.
    The "verified_cohort_name" field will only be present if "enabled" is True.

    Example:
        >>> example = {
        >>>               "enabled": True,
        >>>               "verified_cohort_name" : "Micromasters"
        >>>           }
    """
    course_key = CourseKey.from_string(course_key_string)
    get_course_with_access(request.user, 'staff', course_key)

    settings = {}
    verified_track_cohort_enabled = VerifiedTrackCohortedCourse.is_verified_track_cohort_enabled(course_key)
    settings['enabled'] = verified_track_cohort_enabled
    if verified_track_cohort_enabled:
        settings['verified_cohort_name'] = VerifiedTrackCohortedCourse.verified_cohort_name_for_course(course_key)

    return JsonResponse(settings)
Beispiel #34
0
def _get_course(course_key, user):
    """
    Get the course descriptor, raising CourseNotFoundError if the course is not found or
    the user cannot access forums for the course, and DiscussionDisabledError if the
    discussion tab is disabled for the course.
    """
    try:
        course = get_course_with_access(user, 'load', course_key, check_if_enrolled=True)
    except Http404:
        # Convert 404s into CourseNotFoundErrors.
        raise CourseNotFoundError("Course not found.")
    except CourseAccessRedirect:
        # Raise course not found if the user cannot access the course
        # since it doesn't make sense to redirect an API.
        raise CourseNotFoundError("Course not found.")
    if not any([tab.type == 'discussion' and tab.is_enabled(course, user) for tab in course.tabs]):
        raise DiscussionDisabledError("Discussion is disabled for the course.")
    return course
Beispiel #35
0
 def _wrapper(self, request, *args, **kwargs):
     """
     Expects kwargs to contain 'course_id'.
     Passes the course descriptor to the given decorated function.
     Raises 404 if access to course is disallowed.
     """
     course_id = CourseKey.from_string(kwargs.pop('course_id'))
     with modulestore().bulk_operations(course_id):
         try:
             course = get_course_with_access(
                 request.user,
                 access_action,
                 course_id,
                 depth=depth,
                 check_if_enrolled=True,
             )
         except CoursewareAccessException as error:
             return response.Response(data=error.to_json(), status=status.HTTP_404_NOT_FOUND)
         return func(self, request, course=course, *args, **kwargs)
Beispiel #36
0
    def get(self, request, course_id):
        """
        Gets a course progress status.

        Args:
            request (Request): Django request object.
            course_id (string): URI element specifying the course location.

        Return:
            A JSON serialized representation of the requesting user's current grade status.
        """
        username = request.GET.get('username')

        # only the student can access her own grade status info
        if request.user.username != username:
            log.info(
                'User %s tried to access the grade for user %s.',
                request.user.username,
                username
            )
            return self.make_error_response(
                status_code=status.HTTP_404_NOT_FOUND,
                developer_message='The user requested does not match the logged in user.',
                error_code='user_mismatch'
            )

        # build the course key
        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            return self.make_error_response(
                status_code=status.HTTP_404_NOT_FOUND,
                developer_message='The provided course key cannot be parsed.',
                error_code='invalid_course_key'
            )
        # load the course
        try:
            course = courses.get_course_with_access(
                request.user,
                'load',
                course_key,
                depth=None,
                check_if_enrolled=True
            )
        except Http404:
            log.info('Course with ID "%s" not found', course_id)
            return self.make_error_response(
                status_code=status.HTTP_404_NOT_FOUND,
                developer_message='The user, the course or both do not exist.',
                error_code='user_or_course_does_not_exist'
            )
        prep_course_for_grading(course, request)
        course_grade = CourseGradeFactory(request.user).create(course)
        if not course_grade.has_access_to_course:
            # This means the student didn't have access to the course
            log.info('User %s not allowed to access grade for course %s', request.user.username, username)
            return self.make_error_response(
                status_code=status.HTTP_403_FORBIDDEN,
                developer_message='The user does not have access to the course.',
                error_code='user_does_not_have_access_to_course'
            )

        return Response([{
            'username': username,
            'course_key': course_id,
            'passed': course_grade.passed,
            'percent': course_grade.percent,
            'letter_grade': course_grade.letter_grade,
        }])
Beispiel #37
0
    def get(self, request, course_id):
        """
        Displays the user's Learner Analytics for the specified course.

        Arguments:
            request: HTTP request
            course_id (unicode): course id
        """
        course_key = CourseKey.from_string(course_id)
        if not ENABLE_DASHBOARD_TAB.is_enabled(course_key):
            raise Http404

        course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
        course_url_name = default_course_url_name(course.id)
        course_url = reverse(course_url_name, kwargs={'course_id': unicode(course.id)})

        is_verified = CourseEnrollment.is_enrolled_as_verified(request.user, course_key)
        has_access = is_verified or request.user.is_staff

        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)

        upgrade_price = None
        upgrade_url = None

        if enrollment and enrollment.upgrade_deadline:
            upgrade_url = EcommerceService().upgrade_url(request.user, course_key)
            upgrade_price = get_cosmetic_verified_display_price(course)

        context = {
            'upgrade_price': upgrade_price,
            'upgrade_link': upgrade_url,
            'course': course,
            'course_url': course_url,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
            'is_self_paced': course.self_paced,
            'is_verified': is_verified,
            'has_access': has_access,
        }

        if (has_access):
            grading_policy = course.grading_policy

            (raw_grade_data, answered_percent, percent_grade) = self.get_grade_data(request.user, course_key, grading_policy['GRADE_CUTOFFS'])
            raw_schedule_data = self.get_assignments_with_due_date(request, course_key)

            grade_data, schedule_data = self.sort_grade_and_schedule_data(raw_grade_data, raw_schedule_data)

            # TODO: LEARNER-3854: Fix hacked defaults with real error handling if implementing Learner Analytics.
            try:
                weekly_active_users = self.get_weekly_course_activity_count(course_key)
                week_streak = self.consecutive_weeks_of_course_activity_for_user(
                    request.user.username, course_key
                )
            except Exception as e:
                logging.exception(e)
                weekly_active_users = 134
                week_streak = 1

            context.update({
                'grading_policy': grading_policy,
                'assignment_grades': grade_data,
                'answered_percent': answered_percent,
                'assignment_schedule': schedule_data,
                'assignment_schedule_raw': raw_schedule_data,
                'profile_image_urls': get_profile_image_urls_for_user(request.user, request),
                'discussion_info': self.get_discussion_data(request, course_key),
                'passing_grade': math.ceil(100 * course.lowest_passing_grade),
                'percent_grade': math.ceil(100 * percent_grade),
                'weekly_active_users': weekly_active_users,
                'week_streak': week_streak,
            })

        return render_to_response('learner_analytics/dashboard.html', context)