Merge pull request #8154 from edx/gprice/discussion-api-comment-list-refs
Add comment list URLs to discussion api threads
This commit is contained in:
@@ -107,7 +107,7 @@ def get_thread_list(request, course_key, page, page_size):
|
||||
discussion_api.views.ThreadViewSet for more detail.
|
||||
"""
|
||||
course = _get_course_or_404(course_key, request.user)
|
||||
context = get_context(course, request.user)
|
||||
context = get_context(course, request)
|
||||
threads, result_page, num_pages, _ = Thread.search({
|
||||
"course_id": unicode(course.id),
|
||||
"group_id": (
|
||||
@@ -169,7 +169,7 @@ def get_comment_list(request, thread_id, endorsed, page, page_size):
|
||||
|
||||
course_key = CourseLocator.from_string(cc_thread["course_id"])
|
||||
course = _get_course_or_404(course_key, request.user)
|
||||
context = get_context(course, request.user, cc_thread)
|
||||
context = get_context(course, request, cc_thread)
|
||||
|
||||
# Ensure user has access to the thread
|
||||
if not context["is_requester_privileged"] and cc_thread["group_id"]:
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
"""
|
||||
Discussion API serializers
|
||||
"""
|
||||
from urllib import urlencode
|
||||
from urlparse import urlunparse
|
||||
|
||||
from django.contrib.auth.models import User as DjangoUser
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
@@ -15,7 +19,7 @@ from lms.lib.comment_client.user import User as CommentClientUser
|
||||
from openedx.core.djangoapps.course_groups.cohorts import get_cohort_names
|
||||
|
||||
|
||||
def get_context(course, requester, thread=None):
|
||||
def get_context(course, request, thread=None):
|
||||
"""
|
||||
Returns a context appropriate for use with ThreadSerializer or
|
||||
(if thread is provided) CommentSerializer.
|
||||
@@ -34,8 +38,10 @@ def get_context(course, requester, thread=None):
|
||||
for role in Role.objects.filter(name=FORUM_ROLE_COMMUNITY_TA, course_id=course.id)
|
||||
for user in role.users.all()
|
||||
}
|
||||
requester = request.user
|
||||
return {
|
||||
# For now, the only groups are cohorts
|
||||
"request": request,
|
||||
"group_ids_to_names": get_cohort_names(course),
|
||||
"is_requester_privileged": requester.id in staff_user_ids or requester.id in ta_user_ids,
|
||||
"staff_user_ids": staff_user_ids,
|
||||
@@ -137,6 +143,9 @@ class ThreadSerializer(_ContentSerializer):
|
||||
following = serializers.SerializerMethodField("get_following")
|
||||
comment_count = serializers.IntegerField(source="comments_count")
|
||||
unread_comment_count = serializers.IntegerField(source="unread_comments_count")
|
||||
comment_list_url = serializers.SerializerMethodField("get_comment_list_url")
|
||||
endorsed_comment_list_url = serializers.SerializerMethodField("get_endorsed_comment_list_url")
|
||||
non_endorsed_comment_list_url = serializers.SerializerMethodField("get_non_endorsed_comment_list_url")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ThreadSerializer, self).__init__(*args, **kwargs)
|
||||
@@ -155,6 +164,32 @@ class ThreadSerializer(_ContentSerializer):
|
||||
"""
|
||||
return obj["id"] in self.context["cc_requester"]["subscribed_thread_ids"]
|
||||
|
||||
def get_comment_list_url(self, obj, endorsed=None):
|
||||
"""
|
||||
Returns the URL to retrieve the thread's comments, optionally including
|
||||
the endorsed query parameter.
|
||||
"""
|
||||
if (
|
||||
(obj["thread_type"] == "question" and endorsed is None) or
|
||||
(obj["thread_type"] == "discussion" and endorsed is not None)
|
||||
):
|
||||
return None
|
||||
path = reverse("comment-list")
|
||||
query_dict = {"thread_id": obj["id"]}
|
||||
if endorsed is not None:
|
||||
query_dict["endorsed"] = endorsed
|
||||
return self.context["request"].build_absolute_uri(
|
||||
urlunparse(("", "", path, "", urlencode(query_dict), ""))
|
||||
)
|
||||
|
||||
def get_endorsed_comment_list_url(self, obj):
|
||||
"""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."""
|
||||
return self.get_comment_list_url(obj, endorsed=False)
|
||||
|
||||
|
||||
class CommentSerializer(_ContentSerializer):
|
||||
"""
|
||||
|
||||
@@ -32,6 +32,7 @@ from django_comment_common.models import (
|
||||
from openedx.core.djangoapps.course_groups.models import CourseUserGroupPartitionGroup
|
||||
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from util.testing import UrlResetMixin
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
@@ -356,8 +357,9 @@ class GetCourseTopicsTest(ModuleStoreTestCase):
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class GetThreadListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
|
||||
class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase):
|
||||
"""Test for get_thread_list"""
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
|
||||
def setUp(self):
|
||||
super(GetThreadListTest, self).setUp()
|
||||
httpretty.reset()
|
||||
@@ -485,6 +487,9 @@ class GetThreadListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
|
||||
"vote_count": 4,
|
||||
"comment_count": 5,
|
||||
"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,
|
||||
},
|
||||
{
|
||||
"id": "test_thread_id_1",
|
||||
@@ -507,6 +512,13 @@ class GetThreadListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
|
||||
"vote_count": 9,
|
||||
"comment_count": 18,
|
||||
"unread_comment_count": 0,
|
||||
"comment_list_url": None,
|
||||
"endorsed_comment_list_url": (
|
||||
"http://testserver/api/discussion/v1/comments/?thread_id=test_thread_id_1&endorsed=True"
|
||||
),
|
||||
"non_endorsed_comment_list_url": (
|
||||
"http://testserver/api/discussion/v1/comments/?thread_id=test_thread_id_1&endorsed=False"
|
||||
),
|
||||
},
|
||||
]
|
||||
self.assertEqual(
|
||||
|
||||
@@ -5,6 +5,9 @@ import itertools
|
||||
|
||||
import ddt
|
||||
import httpretty
|
||||
import mock
|
||||
|
||||
from django.test.client import RequestFactory
|
||||
|
||||
from discussion_api.serializers import CommentSerializer, ThreadSerializer, get_context
|
||||
from discussion_api.tests.utils import (
|
||||
@@ -20,13 +23,15 @@ from django_comment_common.models import (
|
||||
Role,
|
||||
)
|
||||
from student.tests.factories import UserFactory
|
||||
from util.testing import UrlResetMixin
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SerializerTestMixin(CommentsServiceMockMixin):
|
||||
class SerializerTestMixin(CommentsServiceMockMixin, UrlResetMixin):
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
|
||||
def setUp(self):
|
||||
super(SerializerTestMixin, self).setUp()
|
||||
httpretty.reset()
|
||||
@@ -35,6 +40,8 @@ class SerializerTestMixin(CommentsServiceMockMixin):
|
||||
self.maxDiff = None # pylint: disable=invalid-name
|
||||
self.user = UserFactory.create()
|
||||
self.register_get_user_response(self.user)
|
||||
self.request = RequestFactory().get("/dummy")
|
||||
self.request.user = self.user
|
||||
self.course = CourseFactory.create()
|
||||
self.author = UserFactory.create()
|
||||
|
||||
@@ -137,7 +144,7 @@ class ThreadSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
|
||||
Create a serializer with an appropriate context and use it to serialize
|
||||
the given thread, returning the result.
|
||||
"""
|
||||
return ThreadSerializer(thread, context=get_context(self.course, self.user)).data
|
||||
return ThreadSerializer(thread, context=get_context(self.course, self.request)).data
|
||||
|
||||
def test_basic(self):
|
||||
thread = {
|
||||
@@ -182,9 +189,25 @@ class ThreadSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
|
||||
"vote_count": 4,
|
||||
"comment_count": 5,
|
||||
"unread_comment_count": 3,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
}
|
||||
self.assertEqual(self.serialize(thread), expected)
|
||||
|
||||
thread["thread_type"] = "question"
|
||||
expected.update({
|
||||
"type": "question",
|
||||
"comment_list_url": None,
|
||||
"endorsed_comment_list_url": (
|
||||
"http://testserver/api/discussion/v1/comments/?thread_id=test_thread&endorsed=True"
|
||||
),
|
||||
"non_endorsed_comment_list_url": (
|
||||
"http://testserver/api/discussion/v1/comments/?thread_id=test_thread&endorsed=False"
|
||||
),
|
||||
})
|
||||
self.assertEqual(self.serialize(thread), expected)
|
||||
|
||||
def test_group(self):
|
||||
cohort = CohortFactory.create(course_id=self.course.id)
|
||||
serialized = self.serialize(self.make_cs_content({"group_id": cohort.id}))
|
||||
@@ -227,7 +250,7 @@ class CommentSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
|
||||
Create a serializer with an appropriate context and use it to serialize
|
||||
the given comment, returning the result.
|
||||
"""
|
||||
context = get_context(self.course, self.user, make_minimal_cs_thread(thread_data))
|
||||
context = get_context(self.course, self.request, make_minimal_cs_thread(thread_data))
|
||||
return CommentSerializer(comment, context=context).data
|
||||
|
||||
def test_basic(self):
|
||||
|
||||
@@ -158,6 +158,9 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
|
||||
"vote_count": 4,
|
||||
"comment_count": 5,
|
||||
"unread_comment_count": 3,
|
||||
"comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_thread",
|
||||
"endorsed_comment_list_url": None,
|
||||
"non_endorsed_comment_list_url": None,
|
||||
}]
|
||||
self.register_get_threads_response(source_threads, page=1, num_pages=2)
|
||||
response = self.client.get(self.url, {"course_id": unicode(self.course.id)})
|
||||
|
||||
Reference in New Issue
Block a user