Commit fa285e09 by wajeeha-khalid

MA-1189 - Discussion API: implemented GET comment children

parent 450e625d
......@@ -415,7 +415,7 @@ def get_comment_list(request, thread_id, endorsed, page, page_size, mark_as_read
raise Http404
num_pages = (resp_total + page_size - 1) / page_size if resp_total else 1
results = [CommentSerializer(response, context=context).data for response in responses]
results = [CommentSerializer(response, remove_fields=["children"], context=context).data for response in responses]
return get_paginated_data(request, results, page, num_pages)
......@@ -718,6 +718,50 @@ def get_thread(request, thread_id):
return serializer.data
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"])
if cc_thread["thread_type"] == "question":
thread_responses = 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
return get_paginated_data(request, results, page, num_pages)
except CommentClientRequestError:
raise Http404
def delete_thread(request, thread_id):
"""
Delete a thread.
......
......@@ -290,6 +290,15 @@ class CommentSerializer(_ContentSerializer):
non_updatable_fields = NON_UPDATABLE_COMMENT_FIELDS
def __init__(self, *args, **kwargs):
remove_fields = kwargs.pop('remove_fields', None)
super(CommentSerializer, self).__init__(*args, **kwargs)
if remove_fields:
# for multiple fields in a list
for field_name in remove_fields:
self.fields.pop(field_name)
def get_endorsed_by(self, obj):
"""
Returns the username of the endorsing user, if the information is
......
......@@ -1146,7 +1146,6 @@ class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase):
"abuse_flagged": False,
"voted": False,
"vote_count": 4,
"children": [],
"editable_fields": ["abuse_flagged", "voted"],
},
{
......@@ -1166,7 +1165,6 @@ class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase):
"abuse_flagged": True,
"voted": False,
"vote_count": 7,
"children": [],
"editable_fields": ["abuse_flagged", "voted"],
},
]
......
......@@ -662,7 +662,6 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
"endorsed": False,
"abuse_flaggers": [],
"votes": {"up_count": 4},
"children": [],
}]
expected_comments = [{
"id": "test_comment",
......@@ -681,7 +680,6 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
"abuse_flagged": False,
"voted": True,
"vote_count": 4,
"children": [],
"editable_fields": ["abuse_flagged", "voted"],
}]
self.register_get_thread_response({
......@@ -1025,3 +1023,73 @@ class ThreadViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase)
self.register_get_thread_error_response(self.thread_id, 404)
response = self.client.get(self.url)
self.assertEqual(response.status_code, 404)
@httpretty.activate
class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
"""Tests for CommentViewSet Retrieve"""
def setUp(self):
super(CommentViewSetRetrieveTest, self).setUp()
self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"})
self.thread_id = "test_thread"
self.comment_id = "test_comment"
def make_comment_data(self, comment_id, parent_id=None, children=[]): # pylint: disable=W0102
"""
Returns comment dict object as returned by comments service
"""
return make_minimal_cs_comment({
"id": comment_id,
"parent_id": parent_id,
"course_id": unicode(self.course.id),
"thread_id": self.thread_id,
"thread_type": "discussion",
"username": self.user.username,
"user_id": str(self.user.id),
"created_at": "2015-06-03T00:00:00Z",
"updated_at": "2015-06-03T00:00:00Z",
"body": "Original body",
"children": children,
})
def test_basic(self):
self.register_get_user_response(self.user)
cs_comment_child = self.make_comment_data("test_child_comment", self.comment_id, children=[])
cs_comment = self.make_comment_data(self.comment_id, None, [cs_comment_child])
cs_thread = make_minimal_cs_thread({
"id": self.thread_id,
"course_id": unicode(self.course.id),
"children": [cs_comment],
})
self.register_get_thread_response(cs_thread)
self.register_get_comment_response(cs_comment)
expected_response_data = {
"id": "test_child_comment",
"parent_id": self.comment_id,
"thread_id": self.thread_id,
"author": self.user.username,
"author_label": None,
"raw_body": "Original body",
"rendered_body": "<p>Original body</p>",
"created_at": "2015-06-03T00:00:00Z",
"updated_at": "2015-06-03T00:00:00Z",
"children": [],
"endorsed_at": None,
"endorsed": False,
"endorsed_by": None,
"endorsed_by_label": None,
"voted": False,
"vote_count": 0,
"abuse_flagged": False,
"editable_fields": ["abuse_flagged", "raw_body", "voted"]
}
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(json.loads(response.content)['results'][0], expected_response_data)
def test_retrieve_nonexistent_comment(self):
self.register_get_comment_error_response(self.comment_id, 404)
response = self.client.get(self.url)
self.assertEqual(response.status_code, 404)
......@@ -18,6 +18,7 @@ from discussion_api.api import (
delete_thread,
delete_comment,
get_comment_list,
get_response_comments,
get_course,
get_course_topics,
get_thread,
......@@ -25,7 +26,7 @@ from discussion_api.api import (
update_comment,
update_thread,
)
from discussion_api.forms import CommentListGetForm, ThreadListGetForm
from discussion_api.forms import CommentListGetForm, ThreadListGetForm, _PaginationForm
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin
......@@ -299,6 +300,8 @@ class CommentViewSet(_ViewMixin, DeveloperErrorViewMixin, ViewSet):
GET /api/discussion/v1/comments/?thread_id=0123456789abcdef01234567
GET /api/discussion/v1/comments/2123456789abcdef01234555
POST /api/discussion/v1/comments/
{
"thread_id": "0123456789abcdef01234567",
......@@ -310,7 +313,7 @@ class CommentViewSet(_ViewMixin, DeveloperErrorViewMixin, ViewSet):
DELETE /api/discussion/v1/comments/comment_id
**GET Parameters**:
**GET Comment List Parameters**:
* thread_id (required): The thread to retrieve comments for
......@@ -325,6 +328,15 @@ class CommentViewSet(_ViewMixin, DeveloperErrorViewMixin, ViewSet):
* mark_as_read: Will mark the thread of the comments as read. (default
is False)
**GET Child Comment List Parameters**:
* comment_id (required): The comment to retrieve child comments for
* page: The (1-indexed) page to retrieve (default is 1)
* page_size: The number of items per page (default is 10, max is 100)
**POST Parameters**:
* thread_id (required): The thread to post the comment in
......@@ -420,6 +432,22 @@ class CommentViewSet(_ViewMixin, DeveloperErrorViewMixin, ViewSet):
)
)
def retrieve(self, request, comment_id=None):
"""
Implements the GET method for comments against response ID
"""
form = _PaginationForm(request.GET)
if not form.is_valid():
raise ValidationError(form.errors)
return Response(
get_response_comments(
request,
comment_id,
form.cleaned_data["page"],
form.cleaned_data["page_size"]
)
)
def create(self, request):
"""
Implements the POST method for the list endpoint as described in the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment