diff --git a/lms/djangoapps/discussion_api/serializers.py b/lms/djangoapps/discussion_api/serializers.py index 9d9763ea60c0066ed3d0df8ddbf0776d579acda5..c88e9941e0640e3194299cd242a34fa3856da011 100644 --- a/lms/djangoapps/discussion_api/serializers.py +++ b/lms/djangoapps/discussion_api/serializers.py @@ -290,6 +290,7 @@ class CommentSerializer(_ContentSerializer): endorsed_by = serializers.SerializerMethodField() endorsed_by_label = serializers.SerializerMethodField() endorsed_at = serializers.SerializerMethodField() + child_count = serializers.IntegerField(read_only=True) children = serializers.SerializerMethodField(required=False) non_updatable_fields = NON_UPDATABLE_COMMENT_FIELDS diff --git a/lms/djangoapps/discussion_api/tests/test_api.py b/lms/djangoapps/discussion_api/tests/test_api.py index 6bdcf514ab7f404710fb579992be8c6797a66dba..de2bfa7644faf43198ba02ab1dc6c2a4b2ddedfb 100644 --- a/lms/djangoapps/discussion_api/tests/test_api.py +++ b/lms/djangoapps/discussion_api/tests/test_api.py @@ -1136,6 +1136,7 @@ class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase): "endorsed": False, "abuse_flaggers": [], "votes": {"up_count": 4}, + "child_count": 0, "children": [], }, { @@ -1152,6 +1153,7 @@ class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase): "endorsed": False, "abuse_flaggers": [str(self.user.id)], "votes": {"up_count": 7}, + "child_count": 0, "children": [], } ] @@ -1174,6 +1176,7 @@ class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase): "voted": False, "vote_count": 4, "editable_fields": ["abuse_flagged", "voted"], + "child_count": 0, "children": [], }, { @@ -1194,6 +1197,7 @@ class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase): "voted": False, "vote_count": 7, "editable_fields": ["abuse_flagged", "voted"], + "child_count": 0, "children": [], }, ] @@ -1688,7 +1692,8 @@ class CreateCommentTest( "voted": False, "vote_count": 0, "children": [], - "editable_fields": ["abuse_flagged", "raw_body", "voted"] + "editable_fields": ["abuse_flagged", "raw_body", "voted"], + "child_count": 0, } self.assertEqual(actual, expected) expected_url = ( @@ -2377,7 +2382,8 @@ class UpdateCommentTest( "voted": False, "vote_count": 0, "children": [], - "editable_fields": ["abuse_flagged", "raw_body", "voted"] + "editable_fields": ["abuse_flagged", "raw_body", "voted"], + "child_count": 0, } self.assertEqual(actual, expected) self.assertEqual( diff --git a/lms/djangoapps/discussion_api/tests/test_serializers.py b/lms/djangoapps/discussion_api/tests/test_serializers.py index 2b1dc38b924344da6e95bb1cb7bf255f599dc7d9..04f193f9bc0b1b1b65afaa5fa251faed51429f14 100644 --- a/lms/djangoapps/discussion_api/tests/test_serializers.py +++ b/lms/djangoapps/discussion_api/tests/test_serializers.py @@ -312,6 +312,7 @@ class CommentSerializerTest(SerializerTestMixin, SharedModuleStoreTestCase): "abuse_flaggers": [], "votes": {"up_count": 4}, "children": [], + "child_count": 0, } expected = { "id": "test_comment", @@ -332,6 +333,7 @@ class CommentSerializerTest(SerializerTestMixin, SharedModuleStoreTestCase): "vote_count": 4, "children": [], "editable_fields": ["abuse_flagged", "voted"], + "child_count": 0, } self.assertEqual(self.serialize(comment), expected) diff --git a/lms/djangoapps/discussion_api/tests/test_views.py b/lms/djangoapps/discussion_api/tests/test_views.py index 355a834a56d12ffaf6232ce9c376679e33b5c6de..40d764f25a0ee270602b2f1d1a077668f2c14a06 100644 --- a/lms/djangoapps/discussion_api/tests/test_views.py +++ b/lms/djangoapps/discussion_api/tests/test_views.py @@ -884,6 +884,34 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): overrides.setdefault("course_id", unicode(self.course.id)) return make_minimal_cs_thread(overrides) + def expected_response_comment(self, overrides=None): + """ + create expected response data + """ + response_data = { + "id": "test_comment", + "thread_id": self.thread_id, + "parent_id": None, + "author": self.author.username, + "author_label": None, + "created_at": "1970-01-01T00:00:00Z", + "updated_at": "1970-01-01T00:00:00Z", + "raw_body": "dummy", + "rendered_body": "<p>dummy</p>", + "endorsed": False, + "endorsed_by": None, + "endorsed_by_label": None, + "endorsed_at": None, + "abuse_flagged": False, + "voted": False, + "vote_count": 0, + "children": [], + "editable_fields": ["abuse_flagged", "voted"], + "child_count": 0, + } + response_data.update(overrides or {}) + return response_data + def test_thread_id_missing(self): response = self.client.get(self.url) self.assert_response_correct( @@ -918,27 +946,17 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): "endorsed": False, "abuse_flaggers": [], "votes": {"up_count": 4}, + "child_count": 0, + "children": [], }] - expected_comments = [{ - "id": "test_comment", - "thread_id": self.thread_id, - "parent_id": None, - "author": self.author.username, - "author_label": None, - "created_at": "2015-05-11T00:00:00Z", - "updated_at": "2015-05-11T11:11:11Z", - "raw_body": "Test body", - "rendered_body": "<p>Test body</p>", - "endorsed": False, - "endorsed_by": None, - "endorsed_by_label": None, - "endorsed_at": None, - "abuse_flagged": False, + expected_comments = [self.expected_response_comment(overrides={ "voted": True, "vote_count": 4, - "editable_fields": ["abuse_flagged", "voted"], - "children": [], - }] + "raw_body": "Test body", + "rendered_body": "<p>Test body</p>", + "created_at": "2015-05-11T00:00:00Z", + "updated_at": "2015-05-11T11:11:11Z", + })] self.register_get_thread_response({ "id": self.thread_id, "course_id": unicode(self.course.id), @@ -979,7 +997,6 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): "id": self.thread_id, "course_id": unicode(self.course.id), "thread_type": "discussion", - "children": [], "resp_total": 10, })) response = self.client.get( @@ -1060,6 +1077,52 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): }} ) + def test_child_comments_count(self): + self.register_get_user_response(self.user) + response_1 = make_minimal_cs_comment({ + "id": "test_response_1", + "thread_id": self.thread_id, + "user_id": str(self.author.id), + "username": self.author.username, + "child_count": 2, + }) + response_2 = make_minimal_cs_comment({ + "id": "test_response_2", + "thread_id": self.thread_id, + "user_id": str(self.author.id), + "username": self.author.username, + "child_count": 3, + }) + thread = self.make_minimal_cs_thread({ + "id": self.thread_id, + "course_id": unicode(self.course.id), + "thread_type": "discussion", + "children": [response_1, response_2], + "resp_total": 2, + "comments_count": 8, + "unread_comments_count": 0, + + }) + self.register_get_thread_response(thread) + response = self.client.get(self.url, {"thread_id": self.thread_id}) + expected_comments = [ + self.expected_response_comment(overrides={"id": "test_response_1", "child_count": 2}), + self.expected_response_comment(overrides={"id": "test_response_2", "child_count": 3}), + ] + self.assert_response_correct( + response, + 200, + { + "results": expected_comments, + "pagination": { + "count": 2, + "next": None, + "num_pages": 1, + "previous": None, + } + } + ) + @httpretty.activate @disable_signal(api, 'comment_deleted') @@ -1139,6 +1202,7 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): "vote_count": 0, "children": [], "editable_fields": ["abuse_flagged", "raw_body", "voted"], + "child_count": 0, } response = self.client.post( self.url, @@ -1227,6 +1291,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes "vote_count": 0, "children": [], "editable_fields": [], + "child_count": 0, } response_data.update(overrides or {}) return response_data @@ -1429,7 +1494,8 @@ class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase "voted": False, "vote_count": 0, "abuse_flagged": False, - "editable_fields": ["abuse_flagged", "raw_body", "voted"] + "editable_fields": ["abuse_flagged", "raw_body", "voted"], + "child_count": 0, } response = self.client.get(self.url) diff --git a/lms/djangoapps/discussion_api/tests/utils.py b/lms/djangoapps/discussion_api/tests/utils.py index e341443a24a57e3912cd0dc1af945bdf7a43030d..ae0a8078eedad8de582393b0ff56e750182a24fa 100644 --- a/lms/djangoapps/discussion_api/tests/utils.py +++ b/lms/djangoapps/discussion_api/tests/utils.py @@ -371,6 +371,7 @@ def make_minimal_cs_comment(overrides=None): "abuse_flaggers": [], "votes": {"up_count": 0}, "endorsed": False, + "child_count": 0, "children": [], } ret.update(overrides or {}) diff --git a/lms/lib/comment_client/comment.py b/lms/lib/comment_client/comment.py index cc7c097c197e2b3bbe02dd926f318fb0ce85a857..ae6f89921c8d7f37c77492d39d3e59252b82b370 100644 --- a/lms/lib/comment_client/comment.py +++ b/lms/lib/comment_client/comment.py @@ -12,6 +12,7 @@ class Comment(models.Model): 'endorsed', 'parent_id', 'thread_id', 'username', 'votes', 'user_id', 'closed', 'created_at', 'updated_at', 'depth', 'at_position_list', 'type', 'commentable_id', 'abuse_flaggers', 'endorsement', + 'child_count', ] updatable_fields = [