コード例 #1
0
ファイル: views.py プロジェクト: colaraz/edx-platform
def user_profile(request, course_key, user_id):
    """
    Renders a response to display the user profile page (shown after clicking
    on a post author's username).
    """
    try:
        context = create_user_profile_context(request, course_key, user_id)
        context['threads'] = add_user_fullname_in_threads(context['threads'])
        if request.is_ajax():
            return utils.JsonResponse({
                'discussion_data':
                context['threads'],
                'page':
                context['page'],
                'num_pages':
                context['num_pages'],
                'annotated_content_info':
                context['annotated_content_info'],
            })
        else:
            tab_view = CourseTabView()

            # To avoid mathjax loading from 'mathjax_include.html'
            # as that file causes multiple loadings of Mathjax on
            # 'user_profile' page
            context['load_mathjax'] = False

            return tab_view.get(request,
                                unicode(course_key),
                                'discussion',
                                profile_page_context=context)
    except User.DoesNotExist:
        raise Http404
    except ValueError:
        return HttpResponseServerError("Invalid group_id")
コード例 #2
0
ファイル: views.py プロジェクト: colaraz/edx-platform
def forum_form_discussion(request, course_key):
    """
    Renders the main Discussion page, potentially filtered by a search query
    """
    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():
        user = cc.User.from_django_user(request.user)
        user_info = user.to_dict()

        try:
            unsafethreads, query_params = get_threads(
                request, course,
                user_info)  # This might process a search query
            is_staff = has_permission(request.user, 'openclose_thread',
                                      course.id)
            threads = [
                utils.prepare_content(thread, course_key, is_staff)
                for thread in unsafethreads
            ]
        except cc.utils.CommentClientMaintenanceError:
            return HttpResponseServerError(
                'Forum is in maintenance mode',
                status=status.HTTP_503_SERVICE_UNAVAILABLE)
        except ValueError:
            return HttpResponseServerError("Invalid group_id")

        with function_trace("get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(
                course_key, threads, request.user, user_info)

        with function_trace("add_courseware_context"):
            add_courseware_context(threads, course, request.user)

        return utils.JsonResponse({
            'discussion_data':
            add_user_fullname_in_threads(
                threads
            ),  # TODO: Standardize on 'discussion_data' vs 'threads'
            'annotated_content_info':
            annotated_content_info,
            'num_pages':
            query_params['num_pages'],
            'page':
            query_params['page'],
            'corrected_text':
            query_params['corrected_text'],
        })
    else:
        course_id = unicode(course.id)
        tab_view = CourseTabView()
        return tab_view.get(request, course_id, 'discussion')
コード例 #3
0
ファイル: views.py プロジェクト: colaraz/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)
    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)
コード例 #4
0
ファイル: views.py プロジェクト: colaraz/edx-platform
    def render_to_fragment(self,
                           request,
                           course_id=None,
                           discussion_id=None,
                           thread_id=None,
                           profile_page_context=None,
                           **kwargs):
        """
        Render the discussion board to a fragment.

        Args:
            request: The Django request.
            course_id: The id of the course in question.
            discussion_id: An optional discussion ID to be focused upon.
            thread_id: An optional ID of the thread to be shown.

        Returns:
            Fragment: The fragment representing the discussion board
        """
        try:
            course_key = CourseKey.from_string(course_id)
            base_context = _create_base_discussion_view_context(
                request, course_key)
            course_object = get_course_by_id(course_key)
            # Note:
            #   After the thread is rendered in this fragment, an AJAX
            #   request is made and the thread is completely loaded again
            #   (yes, this is something to fix). Because of this, we pass in
            #   raise_event=False to _load_thread_for_viewing avoid duplicate
            #   tracking events.
            thread = (_load_thread_for_viewing(
                request,
                base_context['course'],
                discussion_id=discussion_id,
                thread_id=thread_id,
                raise_event=False,
            ) if thread_id else None)
            context = _create_discussion_board_context(request,
                                                       base_context,
                                                       thread=thread)
            context['threads'] = add_user_fullname_in_threads(
                context['threads'])
            course_expiration_fragment = generate_course_expired_fragment(
                request.user, context['course'])
            context.update({
                'course_expiration_fragment':
                course_expiration_fragment,
                'course_image_url':
                course_image_url(course_object),
                'course_title':
                course_object.display_name_with_default,
                'course_organization':
                course_object.display_org_with_default,
            })
            if profile_page_context:
                # EDUCATOR-2119: styles are hard to reconcile if the profile page isn't also a fragment
                html = render_to_string(
                    'discussion/discussion_profile_page.html',
                    profile_page_context)
            else:
                html = render_to_string(
                    'discussion/discussion_board_fragment.html', context)

            fragment = Fragment(html)
            self.add_fragment_resource_urls(fragment)
            inline_js = render_to_string(
                'discussion/discussion_board_js.template', context)
            fragment.add_javascript(inline_js)
            if not settings.REQUIRE_DEBUG:
                fragment.add_javascript_url(
                    staticfiles_storage.url(
                        'discussion/js/discussion_board_factory.js'))
            return fragment
        except cc.utils.CommentClientMaintenanceError:
            log.warning('Forum is in maintenance mode')
            html = render_to_response('discussion/maintenance_fragment.html', {
                'disable_courseware_js': True,
                'uses_pattern_library': True,
            })
            return Fragment(html)
コード例 #5
0
ファイル: views.py プロジェクト: colaraz/edx-platform
def create_user_profile_context(request, course_key, user_id):
    """ Generate a context dictionary for the user profile. """
    user = cc.User.from_django_user(request.user)
    course = get_course_with_access(request.user,
                                    'load',
                                    course_key,
                                    check_if_enrolled=True)

    # If user is not enrolled in the course, do not proceed.
    django_user = User.objects.get(id=user_id)
    if not CourseEnrollment.is_enrolled(django_user, course.id):
        raise Http404

    query_params = {
        'page': request.GET.get('page', 1),
        'per_page':
        THREADS_PER_PAGE,  # more than threads_per_page to show more activities
    }

    group_id = get_group_id_for_comments_service(request, course_key)
    if group_id is not None:
        query_params['group_id'] = group_id
        profiled_user = cc.User(id=user_id,
                                course_id=course_key,
                                group_id=group_id)
    else:
        profiled_user = cc.User(id=user_id, course_id=course_key)

    threads, page, num_pages = profiled_user.active_threads(query_params)
    query_params['page'] = page
    query_params['num_pages'] = num_pages

    with function_trace("get_metadata_for_threads"):
        user_info = cc.User.from_django_user(request.user).to_dict()
        annotated_content_info = utils.get_metadata_for_threads(
            course_key, threads, request.user, user_info)

    is_staff = has_permission(request.user, 'openclose_thread', course.id)
    threads = [
        utils.prepare_content(thread, course_key, is_staff)
        for thread in threads
    ]
    with function_trace("add_courseware_context"):
        add_courseware_context(threads, course, request.user)

        # TODO: LEARNER-3854: If we actually implement Learner Analytics code, this
        #   code was original protected to not run in user_profile() if is_ajax().
        #   Someone should determine if that is still necessary (i.e. was that ever
        #   called as is_ajax()) and clean this up as necessary.
        user_roles = django_user.roles.filter(
            course_id=course.id).order_by("name").values_list(
                "name", flat=True).distinct()

        with function_trace("get_cohort_info"):
            course_discussion_settings = get_course_discussion_settings(
                course_key)
            user_group_id = get_group_id_for_user(request.user,
                                                  course_discussion_settings)

        context = _create_base_discussion_view_context(request, course_key)
        context.update({
            'django_user':
            django_user,
            'django_user_roles':
            user_roles,
            'profiled_user':
            profiled_user.to_dict(),
            'threads':
            add_user_fullname_in_threads(threads),
            'user_group_id':
            user_group_id,
            'annotated_content_info':
            annotated_content_info,
            'page':
            query_params['page'],
            'num_pages':
            query_params['num_pages'],
            'sort_preference':
            user.default_sort_key,
            'learner_profile_page_url':
            reverse('learner_profile',
                    kwargs={'username': django_user.username}),
        })
        return context
コード例 #6
0
ファイル: views.py プロジェクト: colaraz/edx-platform
def _create_discussion_board_context(request, base_context, thread=None):
    """
    Returns the template context for rendering the discussion board.
    """
    context = base_context.copy()
    course = context['course']
    course_key = course.id
    thread_id = thread.id if thread else None
    discussion_id = thread.commentable_id if thread else None
    course_settings = context['course_settings']
    user = context['user']
    cc_user = cc.User.from_django_user(user)
    user_info = context['user_info']
    if thread:

        # 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()]

        for thread in threads:
            # patch for backward compatibility with comments service
            if "pinned" not in thread:
                thread["pinned"] = False
        thread_pages = 1
        root_url = reverse('forum_form_discussion', args=[unicode(course.id)])
    else:
        threads, query_params = get_threads(
            request, course, user_info)  # This might process a search query
        thread_pages = query_params['num_pages']
        root_url = request.path
    is_staff = has_permission(user, 'openclose_thread', course.id)
    threads = [
        utils.prepare_content(thread, course_key, is_staff)
        for thread in threads
    ]

    with function_trace("get_metadata_for_threads"):
        annotated_content_info = utils.get_metadata_for_threads(
            course_key, threads, user, user_info)

    with function_trace("add_courseware_context"):
        add_courseware_context(threads, course, user)

    with function_trace("get_cohort_info"):
        course_discussion_settings = get_course_discussion_settings(course_key)
        user_group_id = get_group_id_for_user(user, course_discussion_settings)

    context.update({
        'root_url':
        root_url,
        'discussion_id':
        discussion_id,
        'thread_id':
        thread_id,
        'threads':
        add_user_fullname_in_threads(threads),
        'thread_pages':
        thread_pages,
        'annotated_content_info':
        annotated_content_info,
        'is_moderator':
        has_permission(user, "see_all_cohorts", course_key),
        'groups':
        course_settings[
            "groups"],  # still needed to render _thread_list_template
        'user_group_id':
        user_group_id,  # read from container in NewPostView
        'sort_preference':
        cc_user.default_sort_key,
        'category_map':
        course_settings["category_map"],
        'course_settings':
        course_settings,
        'is_commentable_divided':
        is_commentable_divided(course_key, discussion_id,
                               course_discussion_settings),
        # If the default topic id is None the front-end code will look for a topic that contains "General"
        'discussion_default_topic_id':
        _get_discussion_default_topic_id(course),
    })
    context.update(get_experiment_user_metadata_context(
        course,
        user,
    ))
    return context
コード例 #7
0
ファイル: views.py プロジェクト: colaraz/edx-platform
def inline_discussion(request, course_key, discussion_id):
    """
    Renders JSON for DiscussionModules
    """

    with function_trace('get_course_and_user_info'):
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        cc_user = cc.User.from_django_user(request.user)
        user_info = cc_user.to_dict()

    try:
        with function_trace('get_threads'):
            threads, query_params = get_threads(
                request,
                course,
                user_info,
                discussion_id,
                per_page=INLINE_THREADS_PER_PAGE)
    except ValueError:
        return HttpResponseServerError('Invalid group_id')

    with function_trace('get_metadata_for_threads'):
        annotated_content_info = utils.get_metadata_for_threads(
            course_key, threads, request.user, user_info)

    with function_trace('determine_group_permissions'):
        is_staff = has_permission(request.user, 'openclose_thread', course.id)
        course_discussion_settings = get_course_discussion_settings(course.id)
        group_names_by_id = get_group_names_by_id(course_discussion_settings)
        course_is_divided = course_discussion_settings.division_scheme is not CourseDiscussionSettings.NONE

    with function_trace('prepare_content'):
        threads = [
            utils.prepare_content(thread, course_key, is_staff,
                                  course_is_divided, group_names_by_id)
            for thread in threads
        ]

    return utils.JsonResponse({
        'is_commentable_divided':
        is_commentable_divided(course_key, discussion_id),
        'discussion_data':
        add_user_fullname_in_threads(threads),
        'user_info':
        user_info,
        'user_group_id':
        get_group_id_for_user(request.user, course_discussion_settings),
        'annotated_content_info':
        annotated_content_info,
        'page':
        query_params['page'],
        'num_pages':
        query_params['num_pages'],
        'roles':
        utils.get_role_ids(course_key),
        'course_settings':
        make_course_settings(course, request.user, False)
    })
コード例 #8
0
def prepare_content(content,
                    course_key,
                    is_staff=False,
                    discussion_division_enabled=None,
                    group_names_by_id=None):
    """
    This function is used to pre-process thread and comment models in various
    ways before adding them to the HTTP response.  This includes fixing empty
    attribute fields, enforcing author anonymity, and enriching metadata around
    group ownership and response endorsement.

    @TODO: not all response pre-processing steps are currently integrated into
    this function.

    Arguments:
        content (dict): A thread or comment.
        course_key (CourseKey): The course key of the course.
        is_staff (bool): Whether the user is a staff member.
        discussion_division_enabled (bool): Whether division of course discussions is enabled.
           Note that callers of this method do not need to provide this value (it defaults to None)--
           it is calculated and then passed to recursive calls of this method.
    """
    fields = [
        'id', 'title', 'body', 'course_id', 'anonymous', 'anonymous_to_peers',
        'endorsed', 'parent_id', 'thread_id', 'votes', 'closed', 'created_at',
        'updated_at', 'depth', 'type', 'commentable_id', 'comments_count',
        'at_position_list', 'children', 'highlighted_title',
        'highlighted_body', 'courseware_title', 'courseware_url',
        'unread_comments_count', 'read', 'group_id', 'group_name', 'pinned',
        'abuse_flaggers', 'stats', 'resp_skip', 'resp_limit', 'resp_total',
        'thread_type', 'endorsed_responses', 'non_endorsed_responses',
        'non_endorsed_resp_total', 'endorsement', 'context', 'last_activity_at'
    ]

    if (content.get('anonymous') is False) and (
        (content.get('anonymous_to_peers') is False) or is_staff):
        fields += ['username', 'user_id']

    content = strip_none(extract(content, fields))

    if content.get("endorsement"):
        endorsement = content["endorsement"]
        endorser = None
        if endorsement["user_id"]:
            try:
                endorser = User.objects.get(pk=endorsement["user_id"])
            except User.DoesNotExist:
                log.error(
                    "User ID %s in endorsement for comment %s but not in our DB.",
                    content.get('user_id'), content.get('id'))

        # Only reveal endorser if requester can see author or if endorser is staff
        if (endorser and
            ("username" in fields
             or has_permission(endorser, "endorse_comment", course_key))):
            endorsement["username"] = endorser.username
        else:
            del endorsement["user_id"]

    if discussion_division_enabled is None:
        discussion_division_enabled = course_discussion_division_enabled(
            get_course_discussion_settings(course_key))

    for child_content_key in [
            "children", "endorsed_responses", "non_endorsed_responses"
    ]:
        if child_content_key in content:
            children = [
                prepare_content(
                    child,
                    course_key,
                    is_staff,
                    discussion_division_enabled=discussion_division_enabled,
                    group_names_by_id=group_names_by_id)
                for child in content[child_content_key]
            ]
            content[child_content_key] = children

    if discussion_division_enabled:
        # Augment the specified thread info to include the group name if a group id is present.
        if content.get('group_id') is not None:
            course_discussion_settings = get_course_discussion_settings(
                course_key)
            if group_names_by_id:
                content['group_name'] = group_names_by_id.get(
                    content.get('group_id'))
            else:
                content['group_name'] = get_group_name(
                    content.get('group_id'), course_discussion_settings)
            content['is_commentable_divided'] = is_commentable_divided(
                course_key, content['commentable_id'],
                course_discussion_settings)
    else:
        # Remove any group information that might remain if the course had previously been divided.
        content.pop('group_id', None)

    # [COLARAZ_CUSTOM] adding profile name of user to thread
    add_user_fullname_in_threads(content)
    return content