예제 #1
0
def index(request, course_id, chapter=None, section=None, position=None):
    """
    Displays courseware accordion and associated content.  If course, chapter,
    and section are all specified, renders the page, or returns an error if they
    are invalid.

    If section is not specified, displays the accordion opened to the right chapter.

    If neither chapter or section are specified, redirects to user's most recent
    chapter, or the first chapter if this is the user's first visit.

    Arguments:

     - request    : HTTP request
     - course_id  : course id (str: ORG/course/URL_NAME)
     - chapter    : chapter url_name (str)
     - section    : section url_name (str)
     - position   : position in module, eg of <sequential> module (str)

    Returns:

     - HTTPresponse
    """
    user = User.objects.prefetch_related("groups").get(id=request.user.id)

    request.user = user  # keep just one instance of User
    course = get_course_with_access(user, course_id, "load", depth=2)
    staff_access = has_access(user, course, "staff")
    registered = registered_for_course(course, user)
    if not registered:
        # TODO (vshnayder): do course instructors need to be registered to see course?
        log.debug("User %s tried to view course %s but is not enrolled" % (user, course.location.url()))
        return redirect(reverse("about_course", args=[course.id]))

    masq = setup_masquerade(request, staff_access)

    try:
        model_data_cache = ModelDataCache.cache_for_descriptor_descendents(course.id, user, course, depth=2)

        course_module = get_module_for_descriptor(user, request, course, model_data_cache, course.id)
        if course_module is None:
            log.warning(
                "If you see this, something went wrong: if we got this"
                " far, should have gotten a course module for this user"
            )
            return redirect(reverse("about_course", args=[course.id]))

        if chapter is None:
            return redirect_to_course_position(course_module)

        # check course constraints
        courses = modulestore().get_items(["i4x", None, None, "course", None])

        def course_filter(course):
            return (
                has_access(user, course, "see_exists")
                # TODO remove this condition when templates purged from db
                and course.location.course != "templates"
                and course.location.org != ""
                and course.location.course != ""
                and course.location.name != ""
            )

        courses = filter(course_filter, courses)
        courses_by_id = dict((course.location.url(), course) for course in courses)
        if not is_item_unlocked(course.unlock_term, courses_by_id, lambda course: grade(user, request, course)):
            raise Http404

        context = {
            "csrf": csrf(request)["csrf_token"],
            "accordion": render_accordion(request, course, chapter, section, model_data_cache),
            "COURSE_TITLE": course.display_name_with_default,
            "course": course,
            "init": "",
            "content": "",
            "staff_access": staff_access,
            "masquerade": masq,
            "xqa_server": settings.MITX_FEATURES.get("USE_XQA_SERVER", "http://*****:*****@content-qa.mitx.mit.edu/xqa"),
        }

        # Only show the chat if it's enabled by the course and in the
        # settings.
        show_chat = course.show_chat and settings.MITX_FEATURES["ENABLE_CHAT"]
        if show_chat:
            context["chat"] = chat_settings(course, user)
            # If we couldn't load the chat settings, then don't show
            # the widget in the courseware.
            if context["chat"] is None:
                show_chat = False

        context["show_chat"] = show_chat

        chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter)
        if chapter_descriptor is not None:
            save_child_position(course_module, chapter)
        else:
            raise Http404("No chapter descriptor found with name {}".format(chapter))

        chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter)
        if chapter_module is None:
            # User may be trying to access a chapter that isn't live yet
            if masq == "student":  # if staff is masquerading as student be kinder, don't 404
                log.debug("staff masq as student: no chapter %s" % chapter)
                return redirect(reverse("courseware", args=[course.id]))
            raise Http404

        if section is not None:
            section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section)

            if section_descriptor is None:
                # Specifically asked-for section doesn't exist
                if masq == "student":  # if staff is masquerading as student be kinder, don't 404
                    log.debug("staff masq as student: no section %s" % section)
                    return redirect(reverse("courseware", args=[course.id]))
                raise Http404

            # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
            # which will prefetch the children more efficiently than doing a recursive load
            section_descriptor = modulestore().get_instance(course.id, section_descriptor.location, depth=None)

            # Load all descendants of the section, because we're going to display its
            # html, which in general will need all of its children
            section_model_data_cache = ModelDataCache.cache_for_descriptor_descendents(
                course_id, user, section_descriptor, depth=None
            )
            section_module = get_module(
                request.user,
                request,
                section_descriptor.location,
                section_model_data_cache,
                course_id,
                position,
                depth=None,
            )

            if section_module is None:
                # User may be trying to be clever and access something
                # they don't have access to.
                raise Http404

            model_data_cache_for_check = ModelDataCache.cache_for_descriptor_descendents(
                course_id, user, course, depth=None
            )

            courseware_summary = grades.progress_summary(user, request, course, model_data_cache_for_check)

            is_section_unlocked = grades.return_section_by_id(section_module.url_name, courseware_summary)["unlocked"]

            # Save where we are in the chapter
            save_child_position(chapter_module, section)

            # check here if this section *is* a timed module.
            if section_module.category == "timelimit":
                timer_context = update_timelimit_module(
                    user, course_id, student_module_cache, section_descriptor, section_module
                )
                if "timer_expiration_duration" in timer_context:
                    context.update(timer_context)
                else:
                    # if there is no expiration defined, then we know the timer has expired:
                    return HttpResponseRedirect(timer_context["time_expired_redirect_url"])
            else:
                # check here if this page is within a course that has an active timed module running.  If so, then
                # add in the appropriate timer information to the rendering context:
                context.update(check_for_active_timelimit_module(request, course_id, course))

            # context['content'] = section_module.runtime.render(section_module, None, 'student_view').content

            if not is_section_unlocked:
                context["content"] = u"Раздел вам пока не доступен"
            else:
                context["content"] = section_module.runtime.render(section_module, None, "student_view").content
                # context['content'] = section_module.get_html()

        else:
            # section is none, so display a message
            prev_section = get_current_child(chapter_module)

            if prev_section is None:
                # Something went wrong -- perhaps this chapter has no sections visible to the user
                raise Http404
            prev_section_url = reverse(
                "courseware_section",
                kwargs={
                    "course_id": course_id,
                    "chapter": chapter_descriptor.url_name,
                    "section": prev_section.url_name,
                },
            )
            context["content"] = render_to_string(
                "courseware/welcome-back.html",
                {
                    "course": course,
                    "chapter_module": chapter_module,
                    "prev_section": prev_section,
                    "prev_section_url": prev_section_url,
                },
            )

        result = render_to_response("courseware/courseware.html", context)
    except Exception as e:
        if isinstance(e, Http404):
            # let it propagate
            raise

        # In production, don't want to let a 500 out for any reason
        if settings.DEBUG:
            raise
        else:
            log.exception(
                "Error in index view: user={user}, course={course},"
                " chapter={chapter} section={section}"
                "position={position}".format(
                    user=user, course=course, chapter=chapter, section=section, position=position
                )
            )
            try:
                result = render_to_response(
                    "courseware/courseware-error.html", {"staff_access": staff_access, "course": course}
                )
            except:
                # Let the exception propagate, relying on global config to at
                # at least return a nice error message
                log.exception("Error while rendering courseware-error page")
                raise

    return result