Commit 09b00df7 by Greg Price

Merge pull request #8154 from edx/gprice/discussion-api-comment-list-refs

Add comment list URLs to discussion api threads
parents c48dccce c83f5615
......@@ -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"]:
......
"""
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)})
......
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