예제 #1
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)
        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)
        with function_trace("add_courseware_context"):
            add_courseware_context([content], course, request.user)

        # [COLARAZ_CUSTOM]
        content = add_user_fullname_in_threads(content)
        if len(content) == 1:
            content = content[0]

        return utils.JsonResponse({
            'content':
            content,
            'annotated_content_info':
            annotated_content_info,
        })
    else:
        course_id = unicode(course.id)
        tab_view = CourseTabView()
        return tab_view.get(request,
                            course_id,
                            'discussion',
                            discussion_id=discussion_id,
                            thread_id=thread_id)
예제 #2
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.
    """
    nr_transaction = newrelic.agent.current_transaction()

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

    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)

        thread = _find_thread(request,
                              course,
                              discussion_id=discussion_id,
                              thread_id=thread_id)
        if not thread:
            raise Http404

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "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)
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context([content], course, request.user)

        return utils.JsonResponse({
            'content':
            content,
            'annotated_content_info':
            annotated_content_info,
        })
    else:
        course_id = unicode(course.id)
        tab_view = CourseTabView()
        return tab_view.get(request,
                            course_id,
                            'discussion',
                            discussion_id=discussion_id,
                            thread_id=thread_id)
예제 #3
0
파일: views.py 프로젝트: mreyk/edx-platform
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)

    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)
        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)
        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 = unicode(course.id)
        tab_view = CourseTabView()
        return tab_view.get(request, course_id, 'discussion', discussion_id=discussion_id, thread_id=thread_id)
예제 #4
0
def single_thread(request, course_key, discussion_id, thread_id):
    """
    Renders a response to display a single discussion thread.
    """
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user,
                                    'load',
                                    course_key,
                                    check_if_enrolled=True)
    course_settings = make_course_settings(course, request.user)
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()
    is_moderator = has_permission(request.user, "see_all_cohorts", course_key)

    # Verify that the student has access to this thread if belongs to a discussion module
    if discussion_id not in utils.get_discussion_categories_ids(
            course, request.user):
        raise Http404

    # Currently, the front end always loads responses via AJAX, even for this
    # page; it would be a nice optimization to avoid that extra round trip to
    # the comments service.
    try:
        thread = cc.Thread.find(thread_id).retrieve(
            recursive=request.is_ajax(),
            user_id=request.user.id,
            response_skip=request.GET.get("resp_skip"),
            response_limit=request.GET.get("resp_limit"))
    except cc.utils.CommentClientRequestError as e:
        if e.status_code == 404:
            raise Http404
        raise

    # verify that the thread belongs to the requesting student's cohort
    if is_commentable_cohorted(course_key, discussion_id) and not is_moderator:
        user_group_id = get_cohort_id(request.user, course_key)
        if getattr(thread, "group_id",
                   None) is not None and user_group_id != thread.group_id:
            raise Http404

    is_staff = has_permission(request.user, 'openclose_thread', course.id)
    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "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)
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context([content], course, request.user)
        return utils.JsonResponse({
            'content':
            content,
            'annotated_content_info':
            annotated_content_info,
        })

    else:
        try:
            threads, query_params = get_threads(request, course)
        except ValueError:
            return HttpResponseBadRequest("Invalid group_id")
        threads.append(thread.to_dict())

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context(threads, course, request.user)

        for thread in threads:
            # patch for backward compatibility with comments service
            if "pinned" not in thread:
                thread["pinned"] = False

        threads = [
            utils.prepare_content(thread, course_key, is_staff)
            for thread in threads
        ]

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(
                course_key, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            user_cohort = get_cohort_id(request.user, course_key)

        context = {
            'discussion_id':
            discussion_id,
            'csrf':
            csrf(request)['csrf_token'],
            'init':
            '',  # TODO: What is this?
            'user_info':
            _attr_safe_json(user_info),
            'annotated_content_info':
            _attr_safe_json(annotated_content_info),
            'course':
            course,
            #'recent_active_threads': recent_active_threads,
            'course_id':
            course.id.to_deprecated_string(
            ),  # TODO: Why pass both course and course.id to template?
            'thread_id':
            thread_id,
            'threads':
            _attr_safe_json(threads),
            'roles':
            _attr_safe_json(utils.get_role_ids(course_key)),
            'is_moderator':
            is_moderator,
            'thread_pages':
            query_params['num_pages'],
            'is_course_cohorted':
            is_course_cohorted(course_key),
            'flag_moderator':
            (has_permission(request.user, 'openclose_thread', course.id)
             or has_access(request.user, 'staff', course)),
            'cohorts':
            course_settings["cohorts"],
            'user_cohort':
            user_cohort,
            'sort_preference':
            cc_user.default_sort_key,
            'category_map':
            course_settings["category_map"],
            'course_settings':
            _attr_safe_json(course_settings)
        }
        return render_to_response('discussion/index.html', context)
예제 #5
0
def single_thread(request, course_key, discussion_id, thread_id):
    """
    Renders a response to display a single discussion thread.
    """
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
    course_settings = make_course_settings(course, request.user)
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()
    is_moderator = has_permission(request.user, "see_all_cohorts", course_key)

    # Currently, the front end always loads responses via AJAX, even for this
    # page; it would be a nice optimization to avoid that extra round trip to
    # the comments service.
    try:
        thread = cc.Thread.find(thread_id).retrieve(
            recursive=request.is_ajax(),
            user_id=request.user.id,
            response_skip=request.GET.get("resp_skip"),
            response_limit=request.GET.get("resp_limit")
        )
    except cc.utils.CommentClientRequestError as error:
        if error.status_code == 404:
            raise Http404
        raise

    # Verify that the student has access to this thread if belongs to a course discussion module
    thread_context = getattr(thread, "context", "course")
    if thread_context == "course" and not utils.discussion_category_id_access(course, request.user, discussion_id):
        raise Http404

    # verify that the thread belongs to the requesting student's cohort
    if is_commentable_cohorted(course_key, discussion_id) and not is_moderator:
        user_group_id = get_cohort_id(request.user, course_key)
        if getattr(thread, "group_id", None) is not None and user_group_id != thread.group_id:
            raise Http404

    is_staff = has_permission(request.user, 'openclose_thread', course.id)
    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction, "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)
        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context([content], course, request.user)
        return utils.JsonResponse({
            'content': content,
            'annotated_content_info': annotated_content_info,
        })

    else:
        try:
            threads, query_params = get_threads(request, course)
        except ValueError:
            return HttpResponseBadRequest("Invalid group_id")
        threads.append(thread.to_dict())

        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context(threads, course, request.user)

        for thread in threads:
            # patch for backward compatibility with comments service
            if "pinned" not in thread:
                thread["pinned"] = False

        threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads]

        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            user_cohort = get_cohort_id(request.user, course_key)

        context = {
            'discussion_id': discussion_id,
            'csrf': csrf(request)['csrf_token'],
            'init': '',   # TODO: What is this?
            'user_info': user_info,
            'can_create_comment': has_permission(request.user, "create_comment", course.id),
            'can_create_subcomment': has_permission(request.user, "create_sub_comment", course.id),
            'can_create_thread': has_permission(request.user, "create_thread", course.id),
            'annotated_content_info': annotated_content_info,
            'course': course,
            #'recent_active_threads': recent_active_threads,
            'course_id': course.id.to_deprecated_string(),   # TODO: Why pass both course and course.id to template?
            'thread_id': thread_id,
            'threads': threads,
            'roles': utils.get_role_ids(course_key),
            'is_moderator': is_moderator,
            'thread_pages': query_params['num_pages'],
            'is_course_cohorted': is_course_cohorted(course_key),
            'flag_moderator': bool(
                has_permission(request.user, 'openclose_thread', course.id) or
                has_access(request.user, 'staff', course)
            ),
            'cohorts': course_settings["cohorts"],
            'user_cohort': user_cohort,
            'sort_preference': cc_user.default_sort_key,
            'category_map': course_settings["category_map"],
            'course_settings': course_settings,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
        }
        return render_to_response('discussion/discussion_board.html', context)
예제 #6
0
def single_thread(request, course_id, discussion_id, thread_id):
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, course_id, 'load_forum')
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()

    # Currently, the front end always loads responses via AJAX, even for this
    # page; it would be a nice optimization to avoid that extra round trip to
    # the comments service.
    try:
        thread = cc.Thread.find(thread_id).retrieve(
            recursive=request.is_ajax(),
            user_id=request.user.id,
            response_skip=request.GET.get("resp_skip"),
            response_limit=request.GET.get("resp_limit"))
    except cc.utils.CommentClientRequestError as e:
        if e.status_code == 404:
            raise Http404
        raise

    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_annotated_content_infos"):
            annotated_content_info = utils.get_annotated_content_infos(
                course_id, thread, request.user, user_info=user_info)
        content = utils.safe_content(thread.to_dict())
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context([content], course)
        return utils.JsonResponse({
            'content':
            content,
            'annotated_content_info':
            annotated_content_info,
        })

    else:
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_discussion_category_map"):
            category_map = utils.get_discussion_category_map(course)

        threads, query_params = get_threads(request, course_id)
        threads.append(thread.to_dict())

        course = get_course_with_access(request.user, course_id, 'load_forum')

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context(threads, course)

        for thread in threads:
            if thread.get('group_id') and not thread.get('group_name'):
                thread['group_name'] = get_cohort_by_id(
                    course_id, thread.get('group_id')).name

            #patch for backward compatibility with comments service
            if not "pinned" in thread:
                thread["pinned"] = False

        threads = [utils.safe_content(thread) for thread in threads]

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(
                course_id, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            cohorts = get_course_cohorts(course_id)
            cohorted_commentables = get_cohorted_commentables(course_id)
            user_cohort = get_cohort_id(request.user, course_id)

        context = {
            'discussion_id':
            discussion_id,
            'csrf':
            csrf(request)['csrf_token'],
            'init':
            '',  # TODO: What is this?
            'user_info':
            saxutils.escape(json.dumps(user_info), escapedict),
            'annotated_content_info':
            saxutils.escape(json.dumps(annotated_content_info), escapedict),
            'course':
            course,
            #'recent_active_threads': recent_active_threads,
            'course_id':
            course.id,  # TODO: Why pass both course and course.id to template?
            'thread_id':
            thread_id,
            'threads':
            saxutils.escape(json.dumps(threads), escapedict),
            'category_map':
            category_map,
            'roles':
            saxutils.escape(json.dumps(utils.get_role_ids(course_id)),
                            escapedict),
            'thread_pages':
            query_params['num_pages'],
            'is_course_cohorted':
            is_course_cohorted(course_id),
            'is_moderator':
            cached_has_permission(request.user, "see_all_cohorts", course_id),
            'flag_moderator':
            cached_has_permission(request.user, 'openclose_thread', course.id)
            or has_access(request.user, course, 'staff'),
            'cohorts':
            cohorts,
            'user_cohort':
            get_cohort_id(request.user, course_id),
            'cohorted_commentables':
            cohorted_commentables
        }

        return render_to_response('discussion/index.html', context)
예제 #7
0
def single_thread(request, course_id, discussion_id, thread_id):
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, course_id, 'load_forum')
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()

    # Currently, the front end always loads responses via AJAX, even for this
    # page; it would be a nice optimization to avoid that extra round trip to
    # the comments service.
    thread = cc.Thread.find(thread_id).retrieve(
        recursive=request.is_ajax(),
        user_id=request.user.id,
        response_skip=request.GET.get("resp_skip"),
        response_limit=request.GET.get("resp_limit")
    )

    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"):
            annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info)
        content = utils.safe_content(thread.to_dict())
        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context([content], course)
        return utils.JsonResponse({
            'content': content,
            'annotated_content_info': annotated_content_info,
        })

    else:
        with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"):
            category_map = utils.get_discussion_category_map(course)

        threads, query_params = get_threads(request, course_id)
        threads.append(thread.to_dict())

        course = get_course_with_access(request.user, course_id, 'load_forum')

        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context(threads, course)

        for thread in threads:
            if thread.get('group_id') and not thread.get('group_name'):
                thread['group_name'] = get_cohort_by_id(course_id, thread.get('group_id')).name

            #patch for backward compatibility with comments service
            if not "pinned" in thread:
                thread["pinned"] = False

        threads = [utils.safe_content(thread) for thread in threads]

        #recent_active_threads = cc.search_recent_active_threads(
        #    course_id,
        #    recursive=False,
        #    query_params={'follower_id': request.user.id},
        #)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(course_id, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            cohorts = get_course_cohorts(course_id)
            cohorted_commentables = get_cohorted_commentables(course_id)
            user_cohort = get_cohort_id(request.user, course_id)

        context = {
            'discussion_id': discussion_id,
            'csrf': csrf(request)['csrf_token'],
            'init': '',   # TODO: What is this?
            'user_info': saxutils.escape(json.dumps(user_info), escapedict),
            'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict),
            'course': course,
            #'recent_active_threads': recent_active_threads,
            'course_id': course.id,   # TODO: Why pass both course and course.id to template?
            'thread_id': thread_id,
            'threads': saxutils.escape(json.dumps(threads), escapedict),
            'category_map': category_map,
            'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict),
            'thread_pages': query_params['num_pages'],
            'is_course_cohorted': is_course_cohorted(course_id),
            'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id),
            'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'),
            'cohorts': cohorts,
            'user_cohort': get_cohort_id(request.user, course_id),
            'cohorted_commentables': cohorted_commentables
        }
        return render_to_response('discussion/index.html', context)
예제 #8
0
def single_thread(request, course_id, discussion_id, thread_id):
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, course_id, 'load_forum')
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()

    thread = cc.Thread.find(thread_id).retrieve(recursive=True,
                                                user_id=request.user.id)

    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_annotated_content_infos"):
            annotated_content_info = utils.get_annotated_content_infos(
                course_id, thread, request.user, user_info=user_info)
        context = {'thread': thread.to_dict(), 'course_id': course_id}
        # TODO: Remove completely or switch back to server side rendering
        # html = render_to_string('discussion/_ajax_single_thread.html', context)
        content = utils.safe_content(thread.to_dict())
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context([content], course)
        return utils.JsonResponse({
            #'html': html,
            'content':
            content,
            'annotated_content_info':
            annotated_content_info,
        })

    else:
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_discussion_category_map"):
            category_map = utils.get_discussion_category_map(course)

        threads, query_params = get_threads(request, course_id)
        threads.append(thread.to_dict())

        course = get_course_with_access(request.user, course_id, 'load_forum')

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context(threads, course)

        for thread in threads:
            if thread.get('group_id') and not thread.get('group_name'):
                thread['group_name'] = get_cohort_by_id(
                    course_id, thread.get('group_id')).name

            #patch for backward compatibility with comments service
            if not "pinned" in thread:
                thread["pinned"] = False

        threads = [utils.safe_content(thread) for thread in threads]

        #recent_active_threads = cc.search_recent_active_threads(
        #    course_id,
        #    recursive=False,
        #    query_params={'follower_id': request.user.id},
        #)

        #trending_tags = cc.search_trending_tags(
        #    course_id,
        #)

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(
                course_id, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            cohorts = get_course_cohorts(course_id)
            cohorted_commentables = get_cohorted_commentables(course_id)
            user_cohort = get_cohort_id(request.user, course_id)

        context = {
            'discussion_id':
            discussion_id,
            'csrf':
            csrf(request)['csrf_token'],
            'init':
            '',  # TODO: What is this?
            'user_info':
            saxutils.escape(json.dumps(user_info), escapedict),
            'annotated_content_info':
            saxutils.escape(json.dumps(annotated_content_info), escapedict),
            'course':
            course,
            #'recent_active_threads': recent_active_threads,
            #'trending_tags': trending_tags,
            'course_id':
            course.id,  # TODO: Why pass both course and course.id to template?
            'thread_id':
            thread_id,
            'threads':
            saxutils.escape(json.dumps(threads), escapedict),
            'category_map':
            category_map,
            'roles':
            saxutils.escape(json.dumps(utils.get_role_ids(course_id)),
                            escapedict),
            'thread_pages':
            query_params['num_pages'],
            'is_course_cohorted':
            is_course_cohorted(course_id),
            'is_moderator':
            cached_has_permission(request.user, "see_all_cohorts", course_id),
            'flag_moderator':
            cached_has_permission(request.user, 'openclose_thread', course.id)
            or has_access(request.user, course, 'staff'),
            'cohorts':
            cohorts,
            'user_cohort':
            get_cohort_id(request.user, course_id),
            'cohorted_commentables':
            cohorted_commentables
        }

        return render_to_response('discussion/single_thread.html', context)
예제 #9
0
파일: views.py 프로젝트: gopinath81/vmss
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.
    """
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user,
                                    'load',
                                    course_key,
                                    check_if_enrolled=True)
    course_settings = make_course_settings(course, request.user)
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()
    is_moderator = has_permission(request.user, "see_all_cohorts", course_key)
    is_staff = has_permission(request.user, 'openclose_thread', course.id)

    try:
        thread = cc.Thread.find(thread_id).retrieve(
            with_responses=request.is_ajax(),
            recursive=request.is_ajax(),
            user_id=request.user.id,
            response_skip=request.GET.get("resp_skip"),
            response_limit=request.GET.get("resp_limit"))
    except cc.utils.CommentClientRequestError as error:
        if error.status_code == 404:
            raise Http404
        raise

    # Verify that the student has access to this thread if belongs to a course discussion module
    thread_context = getattr(thread, "context", "course")
    if thread_context == "course" and not utils.discussion_category_id_access(
            course, request.user, discussion_id):
        raise Http404

    # verify that the thread belongs to the requesting student's cohort
    if is_commentable_cohorted(course_key, discussion_id) and not is_moderator:
        user_group_id = get_cohort_id(request.user, course_key)
        if getattr(thread, "group_id",
                   None) is not None and user_group_id != thread.group_id:
            raise Http404

    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "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)
        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context([content], course, request.user)

        return utils.JsonResponse({
            'content':
            content,
            'annotated_content_info':
            annotated_content_info,
        })
    else:
        # Since we're in page render mode, and the discussions UI will request the thread list itself,
        # we need only return the thread information for this one.
        threads = [thread.to_dict()]

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "add_courseware_context"):
            add_courseware_context(threads, course, request.user)

        for thread in threads:
            # patch for backward compatibility with comments service
            if "pinned" not in thread:
                thread["pinned"] = False

        threads = [
            utils.prepare_content(thread, course_key, is_staff)
            for thread in threads
        ]

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(
                course_key, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            user_cohort = get_cohort_id(request.user, course_key)

        context = {
            'discussion_id':
            discussion_id,
            'csrf':
            csrf(request)['csrf_token'],
            'init':
            '',  # TODO: What is this?
            'user_info':
            user_info,
            'can_create_comment':
            has_permission(request.user, "create_comment", course.id),
            'can_create_subcomment':
            has_permission(request.user, "create_sub_comment", course.id),
            'can_create_thread':
            has_permission(request.user, "create_thread", course.id),
            'annotated_content_info':
            annotated_content_info,
            'course':
            course,
            #'recent_active_threads': recent_active_threads,
            'course_id':
            course.id.to_deprecated_string(
            ),  # TODO: Why pass both course and course.id to template?
            'thread_id':
            thread_id,
            'threads':
            threads,
            'roles':
            utils.get_role_ids(course_key),
            'is_moderator':
            is_moderator,
            'thread_pages':
            1,
            'is_course_cohorted':
            is_course_cohorted(course_key),
            'flag_moderator':
            bool(
                has_permission(request.user, 'openclose_thread', course.id)
                or has_access(request.user, 'staff', course)),
            'cohorts':
            course_settings["cohorts"],
            'user_cohort':
            user_cohort,
            'sort_preference':
            cc_user.default_sort_key,
            'category_map':
            course_settings["category_map"],
            'course_settings':
            course_settings,
            'disable_courseware_js':
            True,
            'uses_pattern_library':
            True,
        }
        return render_to_response('discussion/discussion_board.html', context)
예제 #10
0
def single_thread(request, course_id, discussion_id, thread_id):
    course = get_course_with_access(request.user, course_id, 'load_forum')
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()
    try:
        thread = cc.Thread.find(thread_id).retrieve(recursive=True, user_id=request.user.id)
    except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError):
        log.error("Error loading single thread.")
        context = {'window_title':'Message',
                   'error_title':'',
                   'error_message':"This discussion has been deleted. <a href='/dashboard'>Click here</a> to go back to your dashboard. \
                                    For additional help contact <a href='mailto:[email protected]'>[email protected]</a>."}
        return render_to_response('error.html', context)
        # raise Http404
    
    if len(thread.get('children'))<1:
        create_comment_auto_load(request, course_id, thread_id,User.objects.get(id=thread.get("user_id")))
    if request.is_ajax():
        annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info)
        context = {'thread': thread.to_dict(), 'course_id': course_id}
        # TODO: Remove completely or switch back to server side rendering
        # html = render_to_string('discussion/_ajax_single_thread.html', context)
        content = utils.safe_content(thread.to_dict())
        #courseware_context = get_courseware_context(thread, course)
        #if courseware_context:
        #    content.update(courseware_context)
        if thread.get('tags')[0]!='portfolio':
            id_map = get_discussion_id_map(course)
            id = content['commentable_id']
            content_info = None
            if id in id_map:
                location = id_map[id]["location"].url()
                title = id_map[id]["title"]

                url = reverse('jump_to', kwargs={"course_id": course.location.course_id,
                          "location": location})

                content.update({"courseware_url": url, "courseware_title": title})
        return utils.JsonResponse({
            #'html': html,
            'content': content,
            'annotated_content_info': annotated_content_info,
        })

    else:
        category_map = utils.get_discussion_category_map(course)
        id_map = get_discussion_id_map(course)
        try:
            threads, query_params = get_threads_tags(request, course_id)
            threads.append(thread.to_dict())
        except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError):
            log.error("Error loading single thread.")
            raise Http404

        course = get_course_with_access(request.user, course_id, 'load_forum')
        thread_output = []
        for thread in threads:
            #courseware_context = get_courseware_context(thread, course)
            #if courseware_context:
            #    thread.update(courseware_context)
            id = thread['commentable_id']
            content_info = None
            if id in id_map:
                location = id_map[id]["location"].url()
                title = id_map[id]["title"]

                url = reverse('jump_to', kwargs={"course_id": course.location.course_id,
                          "location": location})

                thread.update({"courseware_url": url, "courseware_title": title})
            if thread.get('group_id') and not thread.get('group_name'):
                thread['group_name'] = get_cohort_by_id(course_id, thread.get('group_id')).name

            #patch for backward compatibility with comments service
            if not "pinned" in thread:
                thread["pinned"] = False
            if len(thread.get('tags'))>0:
                #if thread.get('tags')[0]!='portfolio' and str(thread.get('courseware_url')).find('__am')<0:
                if thread.get('tags')[0]!='portfolio' and thread.get('tags')[0]!='aboutme':
                    thread_output.append(thread)
        thread_output = [utils.safe_content(thread) for thread in thread_output]

        #recent_active_threads = cc.search_recent_active_threads(
        #    course_id,
        #    recursive=False,
        #    query_params={'follower_id': request.user.id},
        #)

        #trending_tags = cc.search_trending_tags(
        #    course_id,
        #)

        annotated_content_info = utils.get_metadata_for_threads(course_id, thread_output, request.user, user_info)

        cohorts = get_course_cohorts(course_id)
        cohorted_commentables = get_cohorted_commentables(course_id)
        user_cohort = get_cohort_id(request.user, course_id)

        context = {
            'discussion_id': discussion_id,
            'csrf': csrf(request)['csrf_token'],
            'init': '',   # TODO: What is this?
            'user_info': saxutils.escape(json.dumps(user_info), escapedict),
            'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict),
            'course': course,
            #'recent_active_threads': recent_active_threads,
            #'trending_tags': trending_tags,
            'course_id': course.id,   # TODO: Why pass both course and course.id to template?
            'thread_id': thread_id,
            'threads': saxutils.escape(json.dumps(thread_output), escapedict),
            'category_map': category_map,
            'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict),
            'thread_pages': query_params['num_pages'],
            'is_course_cohorted': is_course_cohorted(course_id),
            'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id),
            'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'),
            'cohorts': cohorts,
            'user_cohort': get_cohort_id(request.user, course_id),
            'cohorted_commentables': cohorted_commentables
        }

        return render_to_response('discussion/single_thread.html', context)
예제 #11
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.
    """
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
    course_settings = make_course_settings(course, request.user)
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()
    is_moderator = has_permission(request.user, "see_all_cohorts", course_key)
    is_staff = has_permission(request.user, 'openclose_thread', course.id)

    try:
        thread = cc.Thread.find(thread_id).retrieve(
            with_responses=request.is_ajax(),
            recursive=request.is_ajax(),
            user_id=request.user.id,
            response_skip=request.GET.get("resp_skip"),
            response_limit=request.GET.get("resp_limit")
        )
    except cc.utils.CommentClientRequestError as error:
        if error.status_code == 404:
            raise Http404
        raise

    # Verify that the student has access to this thread if belongs to a course discussion module
    thread_context = getattr(thread, "context", "course")
    if thread_context == "course" and not utils.discussion_category_id_access(course, request.user, discussion_id):
        raise Http404

    # verify that the thread belongs to the requesting student's cohort
    if is_commentable_cohorted(course_key, discussion_id) and not is_moderator:
        user_group_id = get_cohort_id(request.user, course_key)
        if getattr(thread, "group_id", None) is not None and user_group_id != thread.group_id:
            raise Http404

    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction, "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)
        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context([content], course, request.user)

        return utils.JsonResponse({
            'content': content,
            'annotated_content_info': annotated_content_info,
        })
    else:
        # Since we're in page render mode, and the discussions UI will request the thread list itself,
        # we need only return the thread information for this one.
        threads = [thread.to_dict()]

        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context(threads, course, request.user)

        for thread in threads:
            # patch for backward compatibility with comments service
            if "pinned" not in thread:
                thread["pinned"] = False

        threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads]

        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            user_cohort = get_cohort_id(request.user, course_key)

        context = {
            'discussion_id': discussion_id,
            'csrf': csrf(request)['csrf_token'],
            'init': '',   # TODO: What is this?
            'user_info': user_info,
            'can_create_comment': has_permission(request.user, "create_comment", course.id),
            'can_create_subcomment': has_permission(request.user, "create_sub_comment", course.id),
            'can_create_thread': has_permission(request.user, "create_thread", course.id),
            'annotated_content_info': annotated_content_info,
            'course': course,
            #'recent_active_threads': recent_active_threads,
            'course_id': course.id.to_deprecated_string(),   # TODO: Why pass both course and course.id to template?
            'thread_id': thread_id,
            'threads': threads,
            'roles': utils.get_role_ids(course_key),
            'is_moderator': is_moderator,
            'thread_pages': 1,
            'is_course_cohorted': is_course_cohorted(course_key),
            'flag_moderator': bool(
                has_permission(request.user, 'openclose_thread', course.id) or
                has_access(request.user, 'staff', course)
            ),
            'cohorts': course_settings["cohorts"],
            'user_cohort': user_cohort,
            'sort_preference': cc_user.default_sort_key,
            'category_map': course_settings["category_map"],
            'course_settings': course_settings,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
        }
        return render_to_response('discussion/discussion_board.html', context)
예제 #12
0
def single_thread(request, course_id, discussion_id, thread_id):
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, 'load_forum', course_key)
    course_settings = make_course_settings(course, include_category_map=True)
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()

    # Currently, the front end always loads responses via AJAX, even for this
    # page; it would be a nice optimization to avoid that extra round trip to
    # the comments service.
    try:
        thread = cc.Thread.find(thread_id).retrieve(
            recursive=request.is_ajax(),
            user_id=request.user.id,
            response_skip=request.GET.get("resp_skip"),
            response_limit=request.GET.get("resp_limit")
        )
    except cc.utils.CommentClientRequestError as e:
        if e.status_code == 404:
            raise Http404
        raise

    is_staff = cached_has_permission(request.user, 'openclose_thread', course.id)
    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"):
            annotated_content_info = utils.get_annotated_content_infos(course_key, thread, request.user, user_info=user_info)
        content = utils.safe_content(thread.to_dict(), course_key, is_staff)
        add_thread_group_name(content, course_key)
        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context([content], course)
        return utils.JsonResponse({
            'content': content,
            'annotated_content_info': annotated_content_info,
        })

    else:
        threads, query_params = get_threads(request, course_key)
        threads.append(thread.to_dict())

        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
            add_courseware_context(threads, course)

        for thread in threads:
            add_thread_group_name(thread, course_key)

            #patch for backward compatibility with comments service
            if not "pinned" in thread:
                thread["pinned"] = False

        threads = [utils.safe_content(thread, course_key, is_staff) for thread in threads]

        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            user_cohort = get_cohort_id(request.user, course_key)

        context = {
            'discussion_id': discussion_id,
            'csrf': csrf(request)['csrf_token'],
            'init': '',   # TODO: What is this?
            'user_info': _attr_safe_json(user_info),
            'annotated_content_info': _attr_safe_json(annotated_content_info),
            'course': course,
            #'recent_active_threads': recent_active_threads,
            'course_id': course.id.to_deprecated_string(),   # TODO: Why pass both course and course.id to template?
            'thread_id': thread_id,
            'threads': _attr_safe_json(threads),
            'roles': _attr_safe_json(utils.get_role_ids(course_key)),
            'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_key),
            'thread_pages': query_params['num_pages'],
            'is_course_cohorted': is_course_cohorted(course_key),
            'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, 'staff', course),
            'cohorts': course_settings["cohorts"],
            'user_cohort': user_cohort,
            'sort_preference': cc_user.default_sort_key,
            'category_map': course_settings["category_map"],
            'course_settings': _attr_safe_json(course_settings)
        }
        return render_to_response('discussion/index.html', context)
예제 #13
0
def single_thread(request, course_id, discussion_id, thread_id):
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, course_id, 'load_forum')
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()

    try:
        thread = cc.Thread.find(thread_id).retrieve(recursive=True, user_id=request.user.id)
    except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError):
        log.error("Error loading single thread.")
        raise

    if request.is_ajax():
        with newrelic.agent.FunctionTrace(nr_transaction, "get_courseware_context"):
            courseware_context = get_courseware_context(thread, course)
        with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"):
            annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info)
        context = {'thread': thread.to_dict(), 'course_id': course_id}
        # TODO: Remove completely or switch back to server side rendering
        # html = render_to_string('discussion/_ajax_single_thread.html', context)
        content = utils.safe_content(thread.to_dict())
        if courseware_context:
            content.update(courseware_context)
        return utils.JsonResponse({
            #'html': html,
            'content': content,
            'annotated_content_info': annotated_content_info,
        })

    else:
        with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"):
            category_map = utils.get_discussion_category_map(course)

        try:
            threads, query_params = get_threads(request, course_id)
            threads.append(thread.to_dict())
        except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError):
            log.error("Error loading single thread.")
            raise

        course = get_course_with_access(request.user, course_id, 'load_forum')

        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context_to_threads"):
            for thread in threads:
                courseware_context = get_courseware_context(thread, course)
                if courseware_context:
                    thread.update(courseware_context)
                if thread.get('group_id') and not thread.get('group_name'):
                    thread['group_name'] = get_cohort_by_id(course_id, thread.get('group_id')).name

                #patch for backward compatibility with comments service
                if not "pinned" in thread:
                    thread["pinned"] = False

        threads = [utils.safe_content(thread) for thread in threads]

        #recent_active_threads = cc.search_recent_active_threads(
        #    course_id,
        #    recursive=False,
        #    query_params={'follower_id': request.user.id},
        #)

        #trending_tags = cc.search_trending_tags(
        #    course_id,
        #)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(course_id, threads, request.user, user_info)

        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
            cohorts = get_course_cohorts(course_id)
            cohorted_commentables = get_cohorted_commentables(course_id)
            user_cohort = get_cohort_id(request.user, course_id)

        context = {
            'discussion_id': discussion_id,
            'csrf': csrf(request)['csrf_token'],
            'init': '',   # TODO: What is this?
            'user_info': saxutils.escape(json.dumps(user_info), escapedict),
            'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict),
            'course': course,
            #'recent_active_threads': recent_active_threads,
            #'trending_tags': trending_tags,
            'course_id': course.id,   # TODO: Why pass both course and course.id to template?
            'thread_id': thread_id,
            'threads': saxutils.escape(json.dumps(threads), escapedict),
            'category_map': category_map,
            'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict),
            'thread_pages': query_params['num_pages'],
            'is_course_cohorted': is_course_cohorted(course_id),
            'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id),
            'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'),
            'cohorts': cohorts,
            'user_cohort': get_cohort_id(request.user, course_id),
            'cohorted_commentables': cohorted_commentables
        }

        return render_to_response('discussion/single_thread.html', context)
예제 #14
0
파일: views.py 프로젝트: GbalsaC/bitnamiP
def single_thread(request, course_key, discussion_id, thread_id):
    """
    Renders a response to display a single discussion thread.
    """
    #    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, "load", course_key, check_if_enrolled=True)
    course_settings = make_course_settings(course, request.user)
    cc_user = cc.User.from_django_user(request.user)
    user_info = cc_user.to_dict()
    is_moderator = has_permission(request.user, "see_all_cohorts", course_key)

    # Verify that the student has access to this thread if belongs to a discussion module
    if discussion_id not in utils.get_discussion_categories_ids(course, request.user):
        raise Http404

    # Currently, the front end always loads responses via AJAX, even for this
    # page; it would be a nice optimization to avoid that extra round trip to
    # the comments service.
    try:
        thread = cc.Thread.find(thread_id).retrieve(
            recursive=request.is_ajax(),
            user_id=request.user.id,
            response_skip=request.GET.get("resp_skip"),
            response_limit=request.GET.get("resp_limit"),
        )
    except cc.utils.CommentClientRequestError as e:
        if e.status_code == 404:
            raise Http404
        raise

    # verify that the thread belongs to the requesting student's cohort
    if is_commentable_cohorted(course_key, discussion_id) and not is_moderator:
        user_group_id = get_cohort_id(request.user, course_key)
        if getattr(thread, "group_id", None) is not None and user_group_id != thread.group_id:
            raise Http404

    is_staff = has_permission(request.user, "openclose_thread", course.id)
    if request.is_ajax():
        #        with newrelic.agent.FunctionTrace(nr_transaction, "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)
        #        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
        add_courseware_context([content], course, request.user)
        return utils.JsonResponse({"content": content, "annotated_content_info": annotated_content_info})

    else:
        try:
            threads, query_params = get_threads(request, course)
        except ValueError:
            return HttpResponseBadRequest("Invalid group_id")
        threads.append(thread.to_dict())

        #        with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"):
        add_courseware_context(threads, course, request.user)

        for thread in threads:
            # patch for backward compatibility with comments service
            if "pinned" not in thread:
                thread["pinned"] = False

        threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads]

        #        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
        annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info)

        #        with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"):
        user_cohort = get_cohort_id(request.user, course_key)

        context = {
            "discussion_id": discussion_id,
            "csrf": csrf(request)["csrf_token"],
            "init": "",  # TODO: What is this?
            "user_info": _attr_safe_json(user_info),
            "annotated_content_info": _attr_safe_json(annotated_content_info),
            "course": course,
            #'recent_active_threads': recent_active_threads,
            "course_id": course.id.to_deprecated_string(),  # TODO: Why pass both course and course.id to template?
            "thread_id": thread_id,
            "threads": _attr_safe_json(threads),
            "roles": _attr_safe_json(utils.get_role_ids(course_key)),
            "is_moderator": is_moderator,
            "thread_pages": query_params["num_pages"],
            "is_course_cohorted": is_course_cohorted(course_key),
            "flag_moderator": (
                has_permission(request.user, "openclose_thread", course.id) or has_access(request.user, "staff", course)
            ),
            "cohorts": course_settings["cohorts"],
            "user_cohort": user_cohort,
            "sort_preference": cc_user.default_sort_key,
            "category_map": course_settings["category_map"],
            "course_settings": _attr_safe_json(course_settings),
        }
        return render_to_response("discussion/index.html", context)