MA-2554: DiscussionAPI - fixed unread_comment_count
This commit is contained in:
@@ -76,7 +76,9 @@ def validate_not_blank(value):
|
||||
|
||||
|
||||
class _ContentSerializer(serializers.Serializer):
|
||||
"""A base class for thread and comment serializers."""
|
||||
"""
|
||||
A base class for thread and comment serializers.
|
||||
"""
|
||||
id = serializers.CharField(read_only=True) # pylint: disable=invalid-name
|
||||
author = serializers.SerializerMethodField()
|
||||
author_label = serializers.SerializerMethodField()
|
||||
@@ -121,7 +123,9 @@ class _ContentSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
def get_author(self, obj):
|
||||
"""Returns the author's username, or None if the content is anonymous."""
|
||||
"""
|
||||
Returns the author's username, or None if the content is anonymous.
|
||||
"""
|
||||
return None if self._is_anonymous(obj) else obj["username"]
|
||||
|
||||
def _get_user_label(self, user_id):
|
||||
@@ -136,7 +140,9 @@ class _ContentSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
def get_author_label(self, obj):
|
||||
"""Returns the role label for the content author."""
|
||||
"""
|
||||
Returns the role label for the content author.
|
||||
"""
|
||||
if self._is_anonymous(obj) or obj["user_id"] is None:
|
||||
return None
|
||||
else:
|
||||
@@ -144,7 +150,9 @@ class _ContentSerializer(serializers.Serializer):
|
||||
return self._get_user_label(user_id)
|
||||
|
||||
def get_rendered_body(self, obj):
|
||||
"""Returns the rendered body content."""
|
||||
"""
|
||||
Returns the rendered body content.
|
||||
"""
|
||||
return render_body(obj["body"])
|
||||
|
||||
def get_abuse_flagged(self, obj):
|
||||
@@ -162,11 +170,15 @@ class _ContentSerializer(serializers.Serializer):
|
||||
return obj["id"] in self.context["cc_requester"]["upvoted_ids"]
|
||||
|
||||
def get_vote_count(self, obj):
|
||||
"""Returns the number of votes for the content."""
|
||||
"""
|
||||
Returns the number of votes for the content.
|
||||
"""
|
||||
return obj.get("votes", {}).get("up_count", 0)
|
||||
|
||||
def get_editable_fields(self, obj):
|
||||
"""Return the list of the fields the requester can edit"""
|
||||
"""
|
||||
Return the list of the fields the requester can edit
|
||||
"""
|
||||
return sorted(get_editable_fields(obj, self.context))
|
||||
|
||||
|
||||
@@ -196,7 +208,7 @@ class ThreadSerializer(_ContentSerializer):
|
||||
endorsed_comment_list_url = serializers.SerializerMethodField()
|
||||
non_endorsed_comment_list_url = serializers.SerializerMethodField()
|
||||
read = serializers.BooleanField(required=False)
|
||||
has_endorsed = serializers.BooleanField(read_only=True, source="endorsed")
|
||||
has_endorsed = serializers.BooleanField(source="endorsed", read_only=True)
|
||||
response_count = serializers.IntegerField(source="resp_total", read_only=True, required=False)
|
||||
|
||||
non_updatable_fields = NON_UPDATABLE_THREAD_FIELDS
|
||||
@@ -216,7 +228,9 @@ class ThreadSerializer(_ContentSerializer):
|
||||
return bool(obj["pinned"])
|
||||
|
||||
def get_group_name(self, obj):
|
||||
"""Returns the name of the group identified by the thread's group_id."""
|
||||
"""
|
||||
Returns the name of the group identified by the thread's group_id.
|
||||
"""
|
||||
return self.context["group_ids_to_names"].get(obj["group_id"])
|
||||
|
||||
def get_following(self, obj):
|
||||
@@ -245,22 +259,31 @@ class ThreadSerializer(_ContentSerializer):
|
||||
)
|
||||
|
||||
def get_endorsed_comment_list_url(self, obj):
|
||||
"""Returns the URL to retrieve the thread's endorsed comments."""
|
||||
"""
|
||||
Returns the URL to retrieve the thread's endorsed comments.
|
||||
"""
|
||||
return self.get_comment_list_url(obj, endorsed=True)
|
||||
|
||||
def get_non_endorsed_comment_list_url(self, obj):
|
||||
"""Returns the URL to retrieve the thread's non-endorsed comments."""
|
||||
"""
|
||||
Returns the URL to retrieve the thread's non-endorsed comments.
|
||||
"""
|
||||
return self.get_comment_list_url(obj, endorsed=False)
|
||||
|
||||
def get_comment_count(self, obj):
|
||||
"""Increments comment count to include post and returns total count of
|
||||
contributions (i.e. post + responses + comments) for the thread"""
|
||||
"""
|
||||
Increments comment count to include post and returns total count of
|
||||
contributions (i.e. post + responses + comments) for the thread
|
||||
"""
|
||||
return obj["comments_count"] + 1
|
||||
|
||||
def get_unread_comment_count(self, obj):
|
||||
"""Increments comment count to include post if thread is unread and returns
|
||||
total count of unread contributions (i.e. post + responses + comments) for the thread"""
|
||||
if not obj["read"]:
|
||||
"""
|
||||
Returns the number of unread comments. If the thread has never been read,
|
||||
this additionally includes 1 for the post itself, in addition to its responses and
|
||||
comments.
|
||||
"""
|
||||
if not obj["read"] and obj["comments_count"] == obj["unread_comments_count"]:
|
||||
return obj["unread_comments_count"] + 1
|
||||
return obj["unread_comments_count"]
|
||||
|
||||
@@ -333,7 +356,9 @@ class CommentSerializer(_ContentSerializer):
|
||||
return None
|
||||
|
||||
def get_endorsed_at(self, obj):
|
||||
"""Returns the timestamp for the endorsement, if available."""
|
||||
"""
|
||||
Returns the timestamp for the endorsement, if available.
|
||||
"""
|
||||
endorsement = obj.get("endorsement")
|
||||
return endorsement["time"] if endorsement else None
|
||||
|
||||
|
||||
@@ -645,107 +645,67 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix
|
||||
|
||||
def test_thread_content(self):
|
||||
source_threads = [
|
||||
{
|
||||
"type": "thread",
|
||||
make_minimal_cs_thread({
|
||||
"id": "test_thread_id_0",
|
||||
"course_id": unicode(self.course.id),
|
||||
"commentable_id": "topic_x",
|
||||
"group_id": None,
|
||||
"user_id": str(self.author.id),
|
||||
"username": self.author.username,
|
||||
"anonymous": False,
|
||||
"anonymous_to_peers": False,
|
||||
"created_at": "2015-04-28T00:00:00Z",
|
||||
"updated_at": "2015-04-28T11:11:11Z",
|
||||
"thread_type": "discussion",
|
||||
"user_id": str(self.author.id),
|
||||
"title": "Test Title",
|
||||
"body": "Test body",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"abuse_flaggers": [],
|
||||
"votes": {"up_count": 4},
|
||||
"comments_count": 5,
|
||||
"unread_comments_count": 3,
|
||||
"endorsed": True,
|
||||
"read": True,
|
||||
},
|
||||
{
|
||||
"type": "thread",
|
||||
"created_at": "2015-04-28T00:00:00Z",
|
||||
"updated_at": "2015-04-28T11:11:11Z",
|
||||
}),
|
||||
make_minimal_cs_thread({
|
||||
"id": "test_thread_id_1",
|
||||
"course_id": unicode(self.course.id),
|
||||
"commentable_id": "topic_y",
|
||||
"group_id": self.cohort.id,
|
||||
"user_id": str(self.author.id),
|
||||
"username": self.author.username,
|
||||
"anonymous": False,
|
||||
"anonymous_to_peers": False,
|
||||
"created_at": "2015-04-28T22:22:22Z",
|
||||
"updated_at": "2015-04-28T00:33:33Z",
|
||||
"user_id": str(self.author.id),
|
||||
"thread_type": "question",
|
||||
"title": "Another Test Title",
|
||||
"body": "More content",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"abuse_flaggers": [],
|
||||
"votes": {"up_count": 9},
|
||||
"comments_count": 18,
|
||||
"unread_comments_count": 0,
|
||||
"endorsed": False,
|
||||
"read": False,
|
||||
},
|
||||
"created_at": "2015-04-28T22:22:22Z",
|
||||
"updated_at": "2015-04-28T00:33:33Z",
|
||||
})
|
||||
]
|
||||
expected_threads = [
|
||||
{
|
||||
self.expected_thread_data({
|
||||
"id": "test_thread_id_0",
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "topic_x",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"author": self.author.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-04-28T00:00:00Z",
|
||||
"updated_at": "2015-04-28T11:11:11Z",
|
||||
"type": "discussion",
|
||||
"title": "Test Title",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"topic_id": "topic_x",
|
||||
"vote_count": 4,
|
||||
"comment_count": 6,
|
||||
"unread_comment_count": 3,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread_id_0",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"editable_fields": ["abuse_flagged", "following", "read", "voted"],
|
||||
"has_endorsed": True,
|
||||
"read": True,
|
||||
},
|
||||
{
|
||||
"created_at": "2015-04-28T00:00:00Z",
|
||||
"updated_at": "2015-04-28T11:11:11Z",
|
||||
}),
|
||||
self.expected_thread_data({
|
||||
"id": "test_thread_id_1",
|
||||
"course_id": unicode(self.course.id),
|
||||
"author": self.author.username,
|
||||
"topic_id": "topic_y",
|
||||
"group_id": self.cohort.id,
|
||||
"group_name": self.cohort.name,
|
||||
"author": self.author.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-04-28T22:22:22Z",
|
||||
"updated_at": "2015-04-28T00:33:33Z",
|
||||
"type": "question",
|
||||
"title": "Another Test Title",
|
||||
"raw_body": "More content",
|
||||
"rendered_body": "<p>More content</p>",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 9,
|
||||
"comment_count": 19,
|
||||
"unread_comment_count": 1,
|
||||
"created_at": "2015-04-28T22:22:22Z",
|
||||
"updated_at": "2015-04-28T00:33:33Z",
|
||||
"comment_list_url": None,
|
||||
"endorsed_comment_list_url": (
|
||||
"http://testserver/api/discussion/v1/comments/?thread_id=test_thread_id_1&endorsed=True"
|
||||
@@ -754,9 +714,7 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix
|
||||
"http://testserver/api/discussion/v1/comments/?thread_id=test_thread_id_1&endorsed=False"
|
||||
),
|
||||
"editable_fields": ["abuse_flagged", "following", "read", "voted"],
|
||||
"has_endorsed": False,
|
||||
"read": False,
|
||||
},
|
||||
}),
|
||||
]
|
||||
|
||||
expected_result = make_paginated_api_response(
|
||||
@@ -1479,42 +1437,17 @@ class CreateThreadTest(
|
||||
cs_thread = make_minimal_cs_thread({
|
||||
"id": "test_id",
|
||||
"username": self.user.username,
|
||||
"created_at": "2015-05-19T00:00:00Z",
|
||||
"updated_at": "2015-05-19T00:00:00Z",
|
||||
"read": True,
|
||||
})
|
||||
self.register_post_thread_response(cs_thread)
|
||||
with self.assert_signal_sent(api, 'thread_created', sender=None, user=self.user, exclude_args=('post',)):
|
||||
actual = create_thread(self.request, self.minimal_data)
|
||||
expected = {
|
||||
expected = self.expected_thread_data({
|
||||
"id": "test_id",
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"author": self.user.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-05-19T00:00:00Z",
|
||||
"updated_at": "2015-05-19T00:00:00Z",
|
||||
"type": "discussion",
|
||||
"title": "Test Title",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 1,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_id",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"editable_fields": ["abuse_flagged", "following", "raw_body", "read", "title", "topic_id", "type", "voted"],
|
||||
'read': False,
|
||||
'has_endorsed': False,
|
||||
'response_count': 0,
|
||||
}
|
||||
"read": True,
|
||||
})
|
||||
self.assertEqual(actual, expected)
|
||||
self.assertEqual(
|
||||
httpretty.last_request().parsed_body,
|
||||
@@ -2002,8 +1935,6 @@ class UpdateThreadTest(
|
||||
"commentable_id": "original_topic",
|
||||
"username": self.user.username,
|
||||
"user_id": str(self.user.id),
|
||||
"created_at": "2015-05-29T00:00:00Z",
|
||||
"updated_at": "2015-05-29T00:00:00Z",
|
||||
"thread_type": "discussion",
|
||||
"title": "Original Title",
|
||||
"body": "Original body",
|
||||
@@ -2025,37 +1956,14 @@ class UpdateThreadTest(
|
||||
self.register_thread()
|
||||
with self.assert_signal_sent(api, 'thread_edited', sender=None, user=self.user, exclude_args=('post',)):
|
||||
actual = update_thread(self.request, "test_thread", {"raw_body": "Edited body"})
|
||||
expected = {
|
||||
"id": "test_thread",
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "original_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"author": self.user.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-05-29T00:00:00Z",
|
||||
"updated_at": "2015-05-29T00:00:00Z",
|
||||
"type": "discussion",
|
||||
"title": "Original Title",
|
||||
|
||||
self.assertEqual(actual, self.expected_thread_data({
|
||||
"raw_body": "Edited body",
|
||||
"rendered_body": "<p>Edited body</p>",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 0,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"editable_fields": ["abuse_flagged", "following", "raw_body", "read", "title", "topic_id", "type", "voted"],
|
||||
'read': True,
|
||||
'has_endorsed': False,
|
||||
'response_count': 0
|
||||
}
|
||||
self.assertEqual(actual, expected)
|
||||
"topic_id": "original_topic",
|
||||
"read": True,
|
||||
"title": "Original Title",
|
||||
}))
|
||||
self.assertEqual(
|
||||
httpretty.last_request().parsed_body,
|
||||
{
|
||||
@@ -3096,12 +3004,12 @@ class RetrieveThreadTest(
|
||||
httpretty.reset()
|
||||
httpretty.enable()
|
||||
self.addCleanup(httpretty.disable)
|
||||
self.thread_author = UserFactory.create()
|
||||
self.register_get_user_response(self.thread_author)
|
||||
self.user = UserFactory.create()
|
||||
self.register_get_user_response(self.user)
|
||||
self.request = RequestFactory().get("/test_path")
|
||||
self.request.user = self.thread_author
|
||||
self.request.user = self.user
|
||||
self.thread_id = "test_thread"
|
||||
CourseEnrollmentFactory.create(user=self.thread_author, course_id=self.course.id)
|
||||
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
|
||||
|
||||
def register_thread(self, overrides=None):
|
||||
"""
|
||||
@@ -3113,12 +3021,10 @@ class RetrieveThreadTest(
|
||||
"id": self.thread_id,
|
||||
"course_id": unicode(self.course.id),
|
||||
"commentable_id": "test_topic",
|
||||
"username": self.thread_author.username,
|
||||
"user_id": str(self.thread_author.id),
|
||||
"username": self.user.username,
|
||||
"user_id": str(self.user.id),
|
||||
"title": "Test Title",
|
||||
"body": "Test body",
|
||||
"created_at": "2015-05-29T00:00:00Z",
|
||||
"updated_at": "2015-05-29T00:00:00Z",
|
||||
"resp_total": 0,
|
||||
|
||||
})
|
||||
@@ -3126,38 +3032,11 @@ class RetrieveThreadTest(
|
||||
self.register_get_thread_response(cs_data)
|
||||
|
||||
def test_basic(self):
|
||||
expected_response_data = {
|
||||
"author": self.thread_author.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-05-29T00:00:00Z",
|
||||
"updated_at": "2015-05-29T00:00:00Z",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"editable_fields": ["abuse_flagged", "following", "raw_body", "read", "title", "topic_id", "type", "voted"],
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"title": "Test Title",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 1,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"read": False,
|
||||
"has_endorsed": False,
|
||||
"id": "test_thread",
|
||||
"type": "discussion",
|
||||
"response_count": 2,
|
||||
}
|
||||
self.register_thread({"resp_total": 2})
|
||||
self.assertEqual(get_thread(self.request, self.thread_id), expected_response_data)
|
||||
self.assertEqual(get_thread(self.request, self.thread_id), self.expected_thread_data({
|
||||
"response_count": 2,
|
||||
"unread_comment_count": 1,
|
||||
}))
|
||||
self.assertEqual(httpretty.last_request().method, "GET")
|
||||
|
||||
def test_thread_id_not_found(self):
|
||||
@@ -3166,42 +3045,15 @@ class RetrieveThreadTest(
|
||||
get_thread(self.request, "missing_thread")
|
||||
|
||||
def test_nonauthor_enrolled_in_course(self):
|
||||
expected_response_data = {
|
||||
"author": self.thread_author.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-05-29T00:00:00Z",
|
||||
"updated_at": "2015-05-29T00:00:00Z",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"editable_fields": ["abuse_flagged", "following", "read", "voted"],
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"title": "Test Title",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 1,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"read": False,
|
||||
"has_endorsed": False,
|
||||
"id": "test_thread",
|
||||
"type": "discussion",
|
||||
"response_count": 0,
|
||||
}
|
||||
non_author_user = UserFactory.create()
|
||||
self.register_get_user_response(non_author_user)
|
||||
CourseEnrollmentFactory.create(user=non_author_user, course_id=self.course.id)
|
||||
self.register_thread()
|
||||
self.request.user = non_author_user
|
||||
self.assertEqual(get_thread(self.request, self.thread_id), expected_response_data)
|
||||
self.assertEqual(get_thread(self.request, self.thread_id), self.expected_thread_data({
|
||||
"editable_fields": ["abuse_flagged", "following", "read", "voted"],
|
||||
"unread_comment_count": 1,
|
||||
}))
|
||||
self.assertEqual(httpretty.last_request().method, "GET")
|
||||
|
||||
def test_not_enrolled_in_course(self):
|
||||
@@ -3233,10 +3085,10 @@ class RetrieveThreadTest(
|
||||
the student role is the author and the thread is in the author's cohort.
|
||||
"""
|
||||
cohort_course = CourseFactory.create(cohort_config={"cohorted": course_is_cohorted})
|
||||
CourseEnrollmentFactory.create(user=self.thread_author, course_id=cohort_course.id)
|
||||
cohort = CohortFactory.create(course_id=cohort_course.id, users=[self.thread_author])
|
||||
CourseEnrollmentFactory.create(user=self.user, course_id=cohort_course.id)
|
||||
cohort = CohortFactory.create(course_id=cohort_course.id, users=[self.user])
|
||||
role = Role.objects.create(name=role_name, course_id=cohort_course.id)
|
||||
role.users = [self.thread_author]
|
||||
role.users = [self.user]
|
||||
self.register_thread({
|
||||
"course_id": unicode(cohort_course.id),
|
||||
"group_id": (
|
||||
|
||||
@@ -161,60 +161,27 @@ class ThreadSerializerSerializationTest(SerializerTestMixin, SharedModuleStoreTe
|
||||
return ThreadSerializer(thread, context=get_context(self.course, self.request)).data
|
||||
|
||||
def test_basic(self):
|
||||
thread = {
|
||||
"type": "thread",
|
||||
thread = make_minimal_cs_thread({
|
||||
"id": "test_thread",
|
||||
"course_id": unicode(self.course.id),
|
||||
"commentable_id": "test_topic",
|
||||
"group_id": None,
|
||||
"user_id": str(self.author.id),
|
||||
"username": self.author.username,
|
||||
"anonymous": False,
|
||||
"anonymous_to_peers": False,
|
||||
"created_at": "2015-04-28T00:00:00Z",
|
||||
"updated_at": "2015-04-28T11:11:11Z",
|
||||
"thread_type": "discussion",
|
||||
"title": "Test Title",
|
||||
"body": "Test body",
|
||||
"pinned": True,
|
||||
"closed": False,
|
||||
"abuse_flaggers": [],
|
||||
"votes": {"up_count": 4},
|
||||
"comments_count": 5,
|
||||
"unread_comments_count": 3,
|
||||
"read": False,
|
||||
"endorsed": False,
|
||||
"response_count": None,
|
||||
}
|
||||
expected = {
|
||||
"id": "test_thread",
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
})
|
||||
expected = self.expected_thread_data({
|
||||
"author": self.author.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-04-28T00:00:00Z",
|
||||
"updated_at": "2015-04-28T11:11:11Z",
|
||||
"type": "discussion",
|
||||
"title": "Test Title",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"pinned": True,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 4,
|
||||
"comment_count": 6,
|
||||
"unread_comment_count": 4,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"unread_comment_count": 3,
|
||||
"pinned": True,
|
||||
"editable_fields": ["abuse_flagged", "following", "read", "voted"],
|
||||
"read": False,
|
||||
"has_endorsed": False,
|
||||
}
|
||||
})
|
||||
self.assertEqual(self.serialize(thread), expected)
|
||||
|
||||
thread["thread_type"] = "question"
|
||||
|
||||
@@ -77,12 +77,12 @@ class DiscussionAPIViewTestMixin(ForumsEnableMixin, CommentsServiceMockMixin, Ur
|
||||
cs_thread = make_minimal_cs_thread({
|
||||
"id": "test_thread",
|
||||
"course_id": unicode(self.course.id),
|
||||
"commentable_id": "original_topic",
|
||||
"commentable_id": "test_topic",
|
||||
"username": self.user.username,
|
||||
"user_id": str(self.user.id),
|
||||
"thread_type": "discussion",
|
||||
"title": "Original Title",
|
||||
"body": "Original body",
|
||||
"title": "Test Title",
|
||||
"body": "Test body",
|
||||
})
|
||||
cs_thread.update(overrides or {})
|
||||
self.register_get_thread_response(cs_thread)
|
||||
@@ -318,43 +318,6 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro
|
||||
self.author = UserFactory.create()
|
||||
self.url = reverse("thread-list")
|
||||
|
||||
def make_expected_thread(self, overrides=None):
|
||||
"""
|
||||
Create a sample expected thread for response
|
||||
"""
|
||||
thread = {
|
||||
"id": "test_thread",
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"author": "dummy",
|
||||
"author_label": None,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
"updated_at": "1970-01-01T00:00:00Z",
|
||||
"type": "discussion",
|
||||
"title": "dummy",
|
||||
"raw_body": "dummy",
|
||||
"rendered_body": "<p>dummy</p>",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 1,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"editable_fields": ["abuse_flagged", "following", "read", "voted"],
|
||||
"read": False,
|
||||
"has_endorsed": False,
|
||||
"response_count": 0,
|
||||
}
|
||||
thread.update(overrides or {})
|
||||
return thread
|
||||
|
||||
def create_source_thread(self, overrides=None):
|
||||
"""
|
||||
Create a sample source cs_thread
|
||||
@@ -398,17 +361,15 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro
|
||||
source_threads = [
|
||||
self.create_source_thread({"user_id": str(self.author.id), "username": self.author.username})
|
||||
]
|
||||
expected_threads = [self.make_expected_thread({
|
||||
expected_threads = [self.expected_thread_data({
|
||||
"created_at": "2015-04-28T00:00:00Z",
|
||||
"updated_at": "2015-04-28T11:11:11Z",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"title": "Test Title",
|
||||
"vote_count": 4,
|
||||
"comment_count": 6,
|
||||
"unread_comment_count": 4,
|
||||
"unread_comment_count": 3,
|
||||
"voted": True,
|
||||
"author": self.author.username
|
||||
"author": self.author.username,
|
||||
"editable_fields": ["abuse_flagged", "following", "read", "voted"],
|
||||
})]
|
||||
self.register_get_threads_response(source_threads, page=1, num_pages=2)
|
||||
response = self.client.get(self.url, {"course_id": unicode(self.course.id), "following": ""})
|
||||
@@ -701,8 +662,6 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
|
||||
cs_thread = make_minimal_cs_thread({
|
||||
"id": "test_thread",
|
||||
"username": self.user.username,
|
||||
"created_at": "2015-05-19T00:00:00Z",
|
||||
"updated_at": "2015-05-19T00:00:00Z",
|
||||
"read": True,
|
||||
})
|
||||
self.register_post_thread_response(cs_thread)
|
||||
@@ -713,36 +672,6 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
|
||||
"title": "Test Title",
|
||||
"raw_body": "Test body",
|
||||
}
|
||||
expected_response_data = {
|
||||
"id": "test_thread",
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"author": self.user.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-05-19T00:00:00Z",
|
||||
"updated_at": "2015-05-19T00:00:00Z",
|
||||
"type": "discussion",
|
||||
"title": "Test Title",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 0,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"editable_fields": ["abuse_flagged", "following", "raw_body", "read", "title", "topic_id", "type", "voted"],
|
||||
"read": True,
|
||||
"has_endorsed": False,
|
||||
"response_count": 0,
|
||||
}
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
json.dumps(request_data),
|
||||
@@ -750,7 +679,7 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_data = json.loads(response.content)
|
||||
self.assertEqual(response_data, expected_response_data)
|
||||
self.assertEqual(response_data, self.expected_thread_data({"read": True}))
|
||||
self.assertEqual(
|
||||
httpretty.last_request().parsed_body,
|
||||
{
|
||||
@@ -795,43 +724,6 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
|
||||
super(ThreadViewSetPartialUpdateTest, self).setUp()
|
||||
self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"})
|
||||
|
||||
def expected_response_data(self, overrides=None):
|
||||
"""
|
||||
create expected response data from comment update endpoint
|
||||
"""
|
||||
response_data = {
|
||||
"id": "test_thread",
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "original_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"author": self.user.username,
|
||||
"author_label": None,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
"updated_at": "1970-01-01T00:00:00Z",
|
||||
"type": "discussion",
|
||||
"title": "Original Title",
|
||||
"raw_body": "Original body",
|
||||
"rendered_body": "<p>Original body</p>",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"comment_count": 0,
|
||||
"unread_comment_count": 0,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"editable_fields": [],
|
||||
"read": False,
|
||||
"has_endorsed": False,
|
||||
"response_count": 0,
|
||||
}
|
||||
response_data.update(overrides or {})
|
||||
return response_data
|
||||
|
||||
def test_basic(self):
|
||||
self.register_get_user_response(self.user)
|
||||
self.register_thread({
|
||||
@@ -846,7 +738,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
|
||||
response_data = json.loads(response.content)
|
||||
self.assertEqual(
|
||||
response_data,
|
||||
self.expected_response_data({
|
||||
self.expected_thread_data({
|
||||
"raw_body": "Edited body",
|
||||
"rendered_body": "<p>Edited body</p>",
|
||||
"editable_fields": [
|
||||
@@ -863,9 +755,9 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
|
||||
httpretty.last_request().parsed_body,
|
||||
{
|
||||
"course_id": [unicode(self.course.id)],
|
||||
"commentable_id": ["original_topic"],
|
||||
"commentable_id": ["test_topic"],
|
||||
"thread_type": ["discussion"],
|
||||
"title": ["Original Title"],
|
||||
"title": ["Test Title"],
|
||||
"body": ["Edited body"],
|
||||
"user_id": [str(self.user.id)],
|
||||
"anonymous": ["False"],
|
||||
@@ -903,7 +795,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
|
||||
response_data = json.loads(response.content)
|
||||
self.assertEqual(
|
||||
response_data,
|
||||
self.expected_response_data({
|
||||
self.expected_thread_data({
|
||||
"read": True,
|
||||
"closed": True,
|
||||
"abuse_flagged": value,
|
||||
@@ -938,7 +830,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
|
||||
response_data = json.loads(response.content)
|
||||
self.assertEqual(
|
||||
response_data,
|
||||
self.expected_response_data({
|
||||
self.expected_thread_data({
|
||||
"comment_count": 1,
|
||||
"read": True,
|
||||
"editable_fields": [
|
||||
@@ -966,7 +858,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
|
||||
response_data = json.loads(response.content)
|
||||
self.assertEqual(
|
||||
response_data,
|
||||
self.expected_response_data({
|
||||
self.expected_thread_data({
|
||||
"author": str(thread_owner_user.username),
|
||||
"comment_count": 1,
|
||||
"read": True,
|
||||
@@ -1655,43 +1547,11 @@ class ThreadViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase,
|
||||
"user_id": str(self.user.id),
|
||||
"title": "Test Title",
|
||||
"body": "Test body",
|
||||
"created_at": "2015-05-29T00:00:00Z",
|
||||
"updated_at": "2015-05-29T00:00:00Z"
|
||||
})
|
||||
expected_response_data = {
|
||||
"author": self.user.username,
|
||||
"author_label": None,
|
||||
"created_at": "2015-05-29T00:00:00Z",
|
||||
"updated_at": "2015-05-29T00:00:00Z",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"editable_fields": ["abuse_flagged", "following", "raw_body", "read", "title", "topic_id", "type", "voted"],
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"title": "Test Title",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 1,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"read": False,
|
||||
"has_endorsed": False,
|
||||
"id": "test_thread",
|
||||
"type": "discussion",
|
||||
"response_count": 0,
|
||||
}
|
||||
self.register_get_thread_response(cs_thread)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(json.loads(response.content), expected_response_data)
|
||||
self.assertEqual(json.loads(response.content), self.expected_thread_data({"unread_comment_count": 1}))
|
||||
self.assertEqual(httpretty.last_request().method, "GET")
|
||||
|
||||
def test_retrieve_nonexistent_thread(self):
|
||||
|
||||
@@ -335,6 +335,43 @@ class CommentsServiceMockMixin(object):
|
||||
content_type="application/merge-patch+json"
|
||||
)
|
||||
|
||||
def expected_thread_data(self, overrides=None):
|
||||
"""
|
||||
Returns expected thread data in API response
|
||||
"""
|
||||
response_data = {
|
||||
"author": self.user.username,
|
||||
"author_label": None,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
"updated_at": "1970-01-01T00:00:00Z",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"abuse_flagged": False,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"editable_fields": ["abuse_flagged", "following", "raw_body", "read", "title", "topic_id", "type", "voted"],
|
||||
"course_id": unicode(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"group_id": None,
|
||||
"group_name": None,
|
||||
"title": "Test Title",
|
||||
"pinned": False,
|
||||
"closed": False,
|
||||
"following": False,
|
||||
"comment_count": 1,
|
||||
"unread_comment_count": 0,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
"read": False,
|
||||
"has_endorsed": False,
|
||||
"id": "test_thread",
|
||||
"type": "discussion",
|
||||
"response_count": 0,
|
||||
}
|
||||
response_data.update(overrides or {})
|
||||
return response_data
|
||||
|
||||
|
||||
def make_minimal_cs_thread(overrides=None):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user