Exemple #1
0
def get_response_comments(request, comment_id, page, page_size, requested_fields=None):
    """
    Return the list of comments for the given thread response.

    Arguments:

        request: The django request object used for build_absolute_uri and
          determining the requesting user.

        comment_id: The id of the comment/response to get child comments for.

        page: The page number (1-indexed) to retrieve

        page_size: The number of comments to retrieve per page

        requested_fields: Indicates which additional fields to return for
        each child comment. (i.e. ['profile_image'])

    Returns:

        A paginated result containing a list of comments

    """
    try:
        cc_comment = Comment(id=comment_id).retrieve()
        cc_thread, context = _get_thread_and_context(
            request,
            cc_comment["thread_id"],
            retrieve_kwargs={
                "with_responses": True,
                "recursive": True,
            }
        )
        if cc_thread["thread_type"] == "question":
            thread_responses = itertools.chain(cc_thread["endorsed_responses"], cc_thread["non_endorsed_responses"])
        else:
            thread_responses = cc_thread["children"]
        response_comments = []
        for response in thread_responses:
            if response["id"] == comment_id:
                response_comments = response["children"]
                break

        response_skip = page_size * (page - 1)
        paged_response_comments = response_comments[response_skip:(response_skip + page_size)]
        if len(paged_response_comments) == 0 and page != 1:
            raise PageNotFoundError("Page not found (No results on this page).")

        results = _serialize_discussion_entities(
            request, context, paged_response_comments, requested_fields, DiscussionEntity.comment
        )

        comments_count = len(response_comments)
        num_pages = (comments_count + page_size - 1) / page_size if comments_count else 1
        paginator = DiscussionAPIPagination(request, page, num_pages, comments_count)
        return paginator.get_paginated_response(results)
    except CommentClientRequestError:
        raise CommentNotFoundError("Comment not found")
Exemple #2
0
def get_response_comments(request, comment_id, page, page_size, requested_fields=None):
    """
    Return the list of comments for the given thread response.

    Arguments:

        request: The django request object used for build_absolute_uri and
          determining the requesting user.

        comment_id: The id of the comment/response to get child comments for.

        page: The page number (1-indexed) to retrieve

        page_size: The number of comments to retrieve per page

        requested_fields: Indicates which additional fields to return for
        each child comment. (i.e. ['profile_image'])

    Returns:

        A paginated result containing a list of comments

    """
    try:
        cc_comment = Comment(id=comment_id).retrieve()
        cc_thread, context = _get_thread_and_context(
            request,
            cc_comment["thread_id"],
            retrieve_kwargs={
                "with_responses": True,
                "recursive": True,
            }
        )
        if cc_thread["thread_type"] == "question":
            thread_responses = itertools.chain(cc_thread["endorsed_responses"], cc_thread["non_endorsed_responses"])
        else:
            thread_responses = cc_thread["children"]
        response_comments = []
        for response in thread_responses:
            if response["id"] == comment_id:
                response_comments = response["children"]
                break

        response_skip = page_size * (page - 1)
        paged_response_comments = response_comments[response_skip:(response_skip + page_size)]
        if len(paged_response_comments) == 0 and page != 1:
            raise PageNotFoundError("Page not found (No results on this page).")

        results = _serialize_discussion_entities(
            request, context, paged_response_comments, requested_fields, DiscussionEntity.comment
        )

        comments_count = len(response_comments)
        num_pages = (comments_count + page_size - 1) / page_size if comments_count else 1
        paginator = DiscussionAPIPagination(request, page, num_pages, comments_count)
        return paginator.get_paginated_response(results)
    except CommentClientRequestError:
        raise CommentNotFoundError("Comment not found")
Exemple #3
0
def get_response_comments(request, comment_id, page, page_size):
    """
    Return the list of comments for the given thread response.

    Arguments:

        request: The django request object used for build_absolute_uri and
          determining the requesting user.

        comment_id: The id of the comment/response to get child comments for.

        page: The page number (1-indexed) to retrieve

        page_size: The number of comments to retrieve per page

    Returns:

        A paginated result containing a list of comments

    """
    try:
        cc_comment = Comment(id=comment_id).retrieve()
        cc_thread, context = _get_thread_and_context(
            request,
            cc_comment["thread_id"],
            retrieve_kwargs={
                "recursive": True,
            }
        )
        if cc_thread["thread_type"] == "question":
            thread_responses = itertools.chain(cc_thread["endorsed_responses"], cc_thread["non_endorsed_responses"])
        else:
            thread_responses = cc_thread["children"]
        response_comments = []
        for response in thread_responses:
            if response["id"] == comment_id:
                response_comments = response["children"]
                break

        response_skip = page_size * (page - 1)
        paged_response_comments = response_comments[response_skip:(response_skip + page_size)]
        results = [CommentSerializer(comment, context=context).data for comment in paged_response_comments]

        comments_count = len(response_comments)
        num_pages = (comments_count + page_size - 1) / page_size if comments_count else 1
        paginator = DiscussionAPIPagination(request, page, num_pages)
        return paginator.get_paginated_response(results)
    except CommentClientRequestError:
        raise CommentNotFoundError("Comment not found")
Exemple #4
0
def get_comment_list(request,
                     thread_id,
                     endorsed,
                     page,
                     page_size,
                     requested_fields=None):
    """
    Return the list of comments in the given thread.

    Arguments:

        request: The django request object used for build_absolute_uri and
          determining the requesting user.

        thread_id: The id of the thread to get comments for.

        endorsed: Boolean indicating whether to get endorsed or non-endorsed
          comments (or None for all comments). Must be None for a discussion
          thread and non-None for a question thread.

        page: The page number (1-indexed) to retrieve

        page_size: The number of comments to retrieve per page

        requested_fields: Indicates which additional fields to return for
        each comment. (i.e. ['profile_image'])

    Returns:

        A paginated result containing a list of comments; see
        discussion_api.views.CommentViewSet for more detail.
    """
    response_skip = page_size * (page - 1)
    cc_thread, context = _get_thread_and_context(request,
                                                 thread_id,
                                                 retrieve_kwargs={
                                                     "with_responses": True,
                                                     "recursive": False,
                                                     "user_id":
                                                     request.user.id,
                                                     "response_skip":
                                                     response_skip,
                                                     "response_limit":
                                                     page_size,
                                                 })

    # Responses to discussion threads cannot be separated by endorsed, but
    # responses to question threads must be separated by endorsed due to the
    # existing comments service interface
    if cc_thread["thread_type"] == "question":
        if endorsed is None:
            raise ValidationError(
                {"endorsed": ["This field is required for question threads."]})
        elif endorsed:
            # CS does not apply resp_skip and resp_limit to endorsed responses
            # of a question post
            responses = cc_thread["endorsed_responses"][response_skip:(
                response_skip + page_size)]
            resp_total = len(cc_thread["endorsed_responses"])
        else:
            responses = cc_thread["non_endorsed_responses"]
            resp_total = cc_thread["non_endorsed_resp_total"]
    else:
        if endorsed is not None:
            raise ValidationError({
                "endorsed":
                ["This field may not be specified for discussion threads."]
            })
        responses = cc_thread["children"]
        resp_total = cc_thread["resp_total"]

    # The comments service returns the last page of results if the requested
    # page is beyond the last page, but we want be consistent with DRF's general
    # behavior and return a PageNotFoundError in that case
    if not responses and page != 1:
        raise PageNotFoundError("Page not found (No results on this page).")
    num_pages = (resp_total + page_size - 1) / page_size if resp_total else 1

    results = _serialize_discussion_entities(request, context, responses,
                                             requested_fields,
                                             DiscussionEntity.comment)

    paginator = DiscussionAPIPagination(request, page, num_pages, resp_total)
    return paginator.get_paginated_response(results)
Exemple #5
0
def get_thread_list(
    request,
    course_key,
    page,
    page_size,
    topic_id_list=None,
    text_search=None,
    following=False,
    view=None,
    order_by="last_activity_at",
    order_direction="desc",
    requested_fields=None,
):
    """
    Return the list of all discussion threads pertaining to the given course

    Parameters:

    request: The django request objects used for build_absolute_uri
    course_key: The key of the course to get discussion threads for
    page: The page number (1-indexed) to retrieve
    page_size: The number of threads to retrieve per page
    topic_id_list: The list of topic_ids to get the discussion threads for
    text_search A text search query string to match
    following: If true, retrieve only threads the requester is following
    view: filters for either "unread" or "unanswered" threads
    order_by: The key in which to sort the threads by. The only values are
        "last_activity_at", "comment_count", and "vote_count". The default is
        "last_activity_at".
    order_direction: The direction in which to sort the threads by. The default
        and only value is "desc". This will be removed in a future major
        version.
    requested_fields: Indicates which additional fields to return
        for each thread. (i.e. ['profile_image'])

    Note that topic_id_list, text_search, and following are mutually exclusive.

    Returns:

    A paginated result containing a list of threads; see
    discussion_api.views.ThreadViewSet for more detail.

    Raises:

    ValidationError: if an invalid value is passed for a field.
    ValueError: if more than one of the mutually exclusive parameters is
      provided
    CourseNotFoundError: if the requesting user does not have access to the requested course
    PageNotFoundError: if page requested is beyond the last
    """
    exclusive_param_count = sum(
        1 for param in [topic_id_list, text_search, following] if param)
    if exclusive_param_count > 1:  # pragma: no cover
        raise ValueError(
            "More than one mutually exclusive param passed to get_thread_list")

    cc_map = {
        "last_activity_at": "activity",
        "comment_count": "comments",
        "vote_count": "votes"
    }
    if order_by not in cc_map:
        raise ValidationError({
            "order_by": [
                "Invalid value. '{}' must be 'last_activity_at', 'comment_count', or 'vote_count'"
                .format(order_by)
            ]
        })
    if order_direction != "desc":
        raise ValidationError({
            "order_direction":
            ["Invalid value. '{}' must be 'desc'".format(order_direction)]
        })

    course = _get_course(course_key, request.user)
    context = get_context(course, request)

    query_params = {
        "user_id":
        unicode(request.user.id),
        "group_id":
        (None if context["is_requester_privileged"] else get_cohort_id(
            request.user, course.id)),
        "page":
        page,
        "per_page":
        page_size,
        "text":
        text_search,
        "sort_key":
        cc_map.get(order_by),
    }

    if view:
        if view in ["unread", "unanswered"]:
            query_params[view] = "true"
        else:
            ValidationError({
                "view": [
                    "Invalid value. '{}' must be 'unread' or 'unanswered'".
                    format(view)
                ]
            })

    if following:
        paginated_results = context["cc_requester"].subscribed_threads(
            query_params)
    else:
        query_params["course_id"] = unicode(course.id)
        query_params["commentable_ids"] = ",".join(
            topic_id_list) if topic_id_list else None
        query_params["text"] = text_search
        paginated_results = Thread.search(query_params)
    # The comments service returns the last page of results if the requested
    # page is beyond the last page, but we want be consistent with DRF's general
    # behavior and return a PageNotFoundError in that case
    if paginated_results.page != page:
        raise PageNotFoundError("Page not found (No results on this page).")

    results = _serialize_discussion_entities(request, context,
                                             paginated_results.collection,
                                             requested_fields,
                                             DiscussionEntity.thread)

    paginator = DiscussionAPIPagination(request, paginated_results.page,
                                        paginated_results.num_pages,
                                        paginated_results.thread_count)
    return paginator.get_paginated_response({
        "results":
        results,
        "text_search_rewrite":
        paginated_results.corrected_text,
    })
Exemple #6
0
def get_comment_list(request, thread_id, endorsed, page, page_size, requested_fields=None):
    """
    Return the list of comments in the given thread.

    Arguments:

        request: The django request object used for build_absolute_uri and
          determining the requesting user.

        thread_id: The id of the thread to get comments for.

        endorsed: Boolean indicating whether to get endorsed or non-endorsed
          comments (or None for all comments). Must be None for a discussion
          thread and non-None for a question thread.

        page: The page number (1-indexed) to retrieve

        page_size: The number of comments to retrieve per page

        requested_fields: Indicates which additional fields to return for
        each comment. (i.e. ['profile_image'])

    Returns:

        A paginated result containing a list of comments; see
        discussion_api.views.CommentViewSet for more detail.
    """
    response_skip = page_size * (page - 1)
    cc_thread, context = _get_thread_and_context(
        request,
        thread_id,
        retrieve_kwargs={
            "with_responses": True,
            "recursive": False,
            "user_id": request.user.id,
            "response_skip": response_skip,
            "response_limit": page_size,
        }
    )

    # Responses to discussion threads cannot be separated by endorsed, but
    # responses to question threads must be separated by endorsed due to the
    # existing comments service interface
    if cc_thread["thread_type"] == "question":
        if endorsed is None:
            raise ValidationError({"endorsed": ["This field is required for question threads."]})
        elif endorsed:
            # CS does not apply resp_skip and resp_limit to endorsed responses
            # of a question post
            responses = cc_thread["endorsed_responses"][response_skip:(response_skip + page_size)]
            resp_total = len(cc_thread["endorsed_responses"])
        else:
            responses = cc_thread["non_endorsed_responses"]
            resp_total = cc_thread["non_endorsed_resp_total"]
    else:
        if endorsed is not None:
            raise ValidationError(
                {"endorsed": ["This field may not be specified for discussion threads."]}
            )
        responses = cc_thread["children"]
        resp_total = cc_thread["resp_total"]

    # The comments service returns the last page of results if the requested
    # page is beyond the last page, but we want be consistent with DRF's general
    # behavior and return a PageNotFoundError in that case
    if not responses and page != 1:
        raise PageNotFoundError("Page not found (No results on this page).")
    num_pages = (resp_total + page_size - 1) / page_size if resp_total else 1

    results = _serialize_discussion_entities(request, context, responses, requested_fields, DiscussionEntity.comment)

    paginator = DiscussionAPIPagination(request, page, num_pages, resp_total)
    return paginator.get_paginated_response(results)
Exemple #7
0
def get_thread_list(
        request,
        course_key,
        page,
        page_size,
        topic_id_list=None,
        text_search=None,
        following=False,
        view=None,
        order_by="last_activity_at",
        order_direction="desc",
        requested_fields=None,
):
    """
    Return the list of all discussion threads pertaining to the given course

    Parameters:

    request: The django request objects used for build_absolute_uri
    course_key: The key of the course to get discussion threads for
    page: The page number (1-indexed) to retrieve
    page_size: The number of threads to retrieve per page
    topic_id_list: The list of topic_ids to get the discussion threads for
    text_search A text search query string to match
    following: If true, retrieve only threads the requester is following
    view: filters for either "unread" or "unanswered" threads
    order_by: The key in which to sort the threads by. The only values are
        "last_activity_at", "comment_count", and "vote_count". The default is
        "last_activity_at".
    order_direction: The direction in which to sort the threads by. The default
        and only value is "desc". This will be removed in a future major
        version.
    requested_fields: Indicates which additional fields to return
        for each thread. (i.e. ['profile_image'])

    Note that topic_id_list, text_search, and following are mutually exclusive.

    Returns:

    A paginated result containing a list of threads; see
    discussion_api.views.ThreadViewSet for more detail.

    Raises:

    ValidationError: if an invalid value is passed for a field.
    ValueError: if more than one of the mutually exclusive parameters is
      provided
    CourseNotFoundError: if the requesting user does not have access to the requested course
    PageNotFoundError: if page requested is beyond the last
    """
    exclusive_param_count = sum(1 for param in [topic_id_list, text_search, following] if param)
    if exclusive_param_count > 1:  # pragma: no cover
        raise ValueError("More than one mutually exclusive param passed to get_thread_list")

    cc_map = {"last_activity_at": "activity", "comment_count": "comments", "vote_count": "votes"}
    if order_by not in cc_map:
        raise ValidationError({
            "order_by":
                ["Invalid value. '{}' must be 'last_activity_at', 'comment_count', or 'vote_count'".format(order_by)]
        })
    if order_direction != "desc":
        raise ValidationError({
            "order_direction": ["Invalid value. '{}' must be 'desc'".format(order_direction)]
        })

    course = _get_course(course_key, request.user)
    context = get_context(course, request)

    query_params = {
        "user_id": unicode(request.user.id),
        "group_id": (
            None if context["is_requester_privileged"] else
            get_cohort_id(request.user, course.id)
        ),
        "page": page,
        "per_page": page_size,
        "text": text_search,
        "sort_key": cc_map.get(order_by),
    }

    if view:
        if view in ["unread", "unanswered"]:
            query_params[view] = "true"
        else:
            ValidationError({
                "view": ["Invalid value. '{}' must be 'unread' or 'unanswered'".format(view)]
            })

    if following:
        paginated_results = context["cc_requester"].subscribed_threads(query_params)
    else:
        query_params["course_id"] = unicode(course.id)
        query_params["commentable_ids"] = ",".join(topic_id_list) if topic_id_list else None
        query_params["text"] = text_search
        paginated_results = Thread.search(query_params)
    # The comments service returns the last page of results if the requested
    # page is beyond the last page, but we want be consistent with DRF's general
    # behavior and return a PageNotFoundError in that case
    if paginated_results.page != page:
        raise PageNotFoundError("Page not found (No results on this page).")

    results = _serialize_discussion_entities(
        request, context, paginated_results.collection, requested_fields, DiscussionEntity.thread
    )

    paginator = DiscussionAPIPagination(
        request,
        paginated_results.page,
        paginated_results.num_pages,
        paginated_results.thread_count
    )
    return paginator.get_paginated_response({
        "results": results,
        "text_search_rewrite": paginated_results.corrected_text,
    })