Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
09b00df7
Commit
09b00df7
authored
May 22, 2015
by
Greg Price
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #8154 from edx/gprice/discussion-api-comment-list-refs
Add comment list URLs to discussion api threads
parents
c48dccce
c83f5615
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
80 additions
and
7 deletions
+80
-7
lms/djangoapps/discussion_api/api.py
+2
-2
lms/djangoapps/discussion_api/serializers.py
+36
-1
lms/djangoapps/discussion_api/tests/test_api.py
+13
-1
lms/djangoapps/discussion_api/tests/test_serializers.py
+26
-3
lms/djangoapps/discussion_api/tests/test_views.py
+3
-0
No files found.
lms/djangoapps/discussion_api/api.py
View file @
09b00df7
...
@@ -107,7 +107,7 @@ def get_thread_list(request, course_key, page, page_size):
...
@@ -107,7 +107,7 @@ def get_thread_list(request, course_key, page, page_size):
discussion_api.views.ThreadViewSet for more detail.
discussion_api.views.ThreadViewSet for more detail.
"""
"""
course
=
_get_course_or_404
(
course_key
,
request
.
user
)
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
({
threads
,
result_page
,
num_pages
,
_
=
Thread
.
search
({
"course_id"
:
unicode
(
course
.
id
),
"course_id"
:
unicode
(
course
.
id
),
"group_id"
:
(
"group_id"
:
(
...
@@ -169,7 +169,7 @@ def get_comment_list(request, thread_id, endorsed, page, page_size):
...
@@ -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_key
=
CourseLocator
.
from_string
(
cc_thread
[
"course_id"
])
course
=
_get_course_or_404
(
course_key
,
request
.
user
)
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
# Ensure user has access to the thread
if
not
context
[
"is_requester_privileged"
]
and
cc_thread
[
"group_id"
]:
if
not
context
[
"is_requester_privileged"
]
and
cc_thread
[
"group_id"
]:
...
...
lms/djangoapps/discussion_api/serializers.py
View file @
09b00df7
"""
"""
Discussion API serializers
Discussion API serializers
"""
"""
from
urllib
import
urlencode
from
urlparse
import
urlunparse
from
django.contrib.auth.models
import
User
as
DjangoUser
from
django.contrib.auth.models
import
User
as
DjangoUser
from
django.core.urlresolvers
import
reverse
from
rest_framework
import
serializers
from
rest_framework
import
serializers
...
@@ -15,7 +19,7 @@ from lms.lib.comment_client.user import User as CommentClientUser
...
@@ -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
from
openedx.core.djangoapps.course_groups.cohorts
import
get_cohort_names
def
get_context
(
course
,
request
er
,
thread
=
None
):
def
get_context
(
course
,
request
,
thread
=
None
):
"""
"""
Returns a context appropriate for use with ThreadSerializer or
Returns a context appropriate for use with ThreadSerializer or
(if thread is provided) CommentSerializer.
(if thread is provided) CommentSerializer.
...
@@ -34,8 +38,10 @@ def get_context(course, requester, thread=None):
...
@@ -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
role
in
Role
.
objects
.
filter
(
name
=
FORUM_ROLE_COMMUNITY_TA
,
course_id
=
course
.
id
)
for
user
in
role
.
users
.
all
()
for
user
in
role
.
users
.
all
()
}
}
requester
=
request
.
user
return
{
return
{
# For now, the only groups are cohorts
# For now, the only groups are cohorts
"request"
:
request
,
"group_ids_to_names"
:
get_cohort_names
(
course
),
"group_ids_to_names"
:
get_cohort_names
(
course
),
"is_requester_privileged"
:
requester
.
id
in
staff_user_ids
or
requester
.
id
in
ta_user_ids
,
"is_requester_privileged"
:
requester
.
id
in
staff_user_ids
or
requester
.
id
in
ta_user_ids
,
"staff_user_ids"
:
staff_user_ids
,
"staff_user_ids"
:
staff_user_ids
,
...
@@ -137,6 +143,9 @@ class ThreadSerializer(_ContentSerializer):
...
@@ -137,6 +143,9 @@ class ThreadSerializer(_ContentSerializer):
following
=
serializers
.
SerializerMethodField
(
"get_following"
)
following
=
serializers
.
SerializerMethodField
(
"get_following"
)
comment_count
=
serializers
.
IntegerField
(
source
=
"comments_count"
)
comment_count
=
serializers
.
IntegerField
(
source
=
"comments_count"
)
unread_comment_count
=
serializers
.
IntegerField
(
source
=
"unread_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
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
ThreadSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
ThreadSerializer
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
...
@@ -155,6 +164,32 @@ class ThreadSerializer(_ContentSerializer):
...
@@ -155,6 +164,32 @@ class ThreadSerializer(_ContentSerializer):
"""
"""
return
obj
[
"id"
]
in
self
.
context
[
"cc_requester"
][
"subscribed_thread_ids"
]
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
):
class
CommentSerializer
(
_ContentSerializer
):
"""
"""
...
...
lms/djangoapps/discussion_api/tests/test_api.py
View file @
09b00df7
...
@@ -32,6 +32,7 @@ from django_comment_common.models import (
...
@@ -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.models
import
CourseUserGroupPartitionGroup
from
openedx.core.djangoapps.course_groups.tests.helpers
import
CohortFactory
from
openedx.core.djangoapps.course_groups.tests.helpers
import
CohortFactory
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
util.testing
import
UrlResetMixin
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
...
@@ -356,8 +357,9 @@ class GetCourseTopicsTest(ModuleStoreTestCase):
...
@@ -356,8 +357,9 @@ class GetCourseTopicsTest(ModuleStoreTestCase):
@ddt.ddt
@ddt.ddt
class
GetThreadListTest
(
CommentsServiceMockMixin
,
ModuleStoreTestCase
):
class
GetThreadListTest
(
CommentsServiceMockMixin
,
UrlResetMixin
,
ModuleStoreTestCase
):
"""Test for get_thread_list"""
"""Test for get_thread_list"""
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
):
def
setUp
(
self
):
super
(
GetThreadListTest
,
self
)
.
setUp
()
super
(
GetThreadListTest
,
self
)
.
setUp
()
httpretty
.
reset
()
httpretty
.
reset
()
...
@@ -485,6 +487,9 @@ class GetThreadListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
...
@@ -485,6 +487,9 @@ class GetThreadListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
"vote_count"
:
4
,
"vote_count"
:
4
,
"comment_count"
:
5
,
"comment_count"
:
5
,
"unread_comment_count"
:
3
,
"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"
,
"id"
:
"test_thread_id_1"
,
...
@@ -507,6 +512,13 @@ class GetThreadListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
...
@@ -507,6 +512,13 @@ class GetThreadListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
"vote_count"
:
9
,
"vote_count"
:
9
,
"comment_count"
:
18
,
"comment_count"
:
18
,
"unread_comment_count"
:
0
,
"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
(
self
.
assertEqual
(
...
...
lms/djangoapps/discussion_api/tests/test_serializers.py
View file @
09b00df7
...
@@ -5,6 +5,9 @@ import itertools
...
@@ -5,6 +5,9 @@ import itertools
import
ddt
import
ddt
import
httpretty
import
httpretty
import
mock
from
django.test.client
import
RequestFactory
from
discussion_api.serializers
import
CommentSerializer
,
ThreadSerializer
,
get_context
from
discussion_api.serializers
import
CommentSerializer
,
ThreadSerializer
,
get_context
from
discussion_api.tests.utils
import
(
from
discussion_api.tests.utils
import
(
...
@@ -20,13 +23,15 @@ from django_comment_common.models import (
...
@@ -20,13 +23,15 @@ from django_comment_common.models import (
Role
,
Role
,
)
)
from
student.tests.factories
import
UserFactory
from
student.tests.factories
import
UserFactory
from
util.testing
import
UrlResetMixin
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
openedx.core.djangoapps.course_groups.tests.helpers
import
CohortFactory
from
openedx.core.djangoapps.course_groups.tests.helpers
import
CohortFactory
@ddt.ddt
@ddt.ddt
class
SerializerTestMixin
(
CommentsServiceMockMixin
):
class
SerializerTestMixin
(
CommentsServiceMockMixin
,
UrlResetMixin
):
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
):
def
setUp
(
self
):
super
(
SerializerTestMixin
,
self
)
.
setUp
()
super
(
SerializerTestMixin
,
self
)
.
setUp
()
httpretty
.
reset
()
httpretty
.
reset
()
...
@@ -35,6 +40,8 @@ class SerializerTestMixin(CommentsServiceMockMixin):
...
@@ -35,6 +40,8 @@ class SerializerTestMixin(CommentsServiceMockMixin):
self
.
maxDiff
=
None
# pylint: disable=invalid-name
self
.
maxDiff
=
None
# pylint: disable=invalid-name
self
.
user
=
UserFactory
.
create
()
self
.
user
=
UserFactory
.
create
()
self
.
register_get_user_response
(
self
.
user
)
self
.
register_get_user_response
(
self
.
user
)
self
.
request
=
RequestFactory
()
.
get
(
"/dummy"
)
self
.
request
.
user
=
self
.
user
self
.
course
=
CourseFactory
.
create
()
self
.
course
=
CourseFactory
.
create
()
self
.
author
=
UserFactory
.
create
()
self
.
author
=
UserFactory
.
create
()
...
@@ -137,7 +144,7 @@ class ThreadSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
...
@@ -137,7 +144,7 @@ class ThreadSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
Create a serializer with an appropriate context and use it to serialize
Create a serializer with an appropriate context and use it to serialize
the given thread, returning the result.
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
):
def
test_basic
(
self
):
thread
=
{
thread
=
{
...
@@ -182,9 +189,25 @@ class ThreadSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
...
@@ -182,9 +189,25 @@ class ThreadSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
"vote_count"
:
4
,
"vote_count"
:
4
,
"comment_count"
:
5
,
"comment_count"
:
5
,
"unread_comment_count"
:
3
,
"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
)
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
):
def
test_group
(
self
):
cohort
=
CohortFactory
.
create
(
course_id
=
self
.
course
.
id
)
cohort
=
CohortFactory
.
create
(
course_id
=
self
.
course
.
id
)
serialized
=
self
.
serialize
(
self
.
make_cs_content
({
"group_id"
:
cohort
.
id
}))
serialized
=
self
.
serialize
(
self
.
make_cs_content
({
"group_id"
:
cohort
.
id
}))
...
@@ -227,7 +250,7 @@ class CommentSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
...
@@ -227,7 +250,7 @@ class CommentSerializerTest(SerializerTestMixin, ModuleStoreTestCase):
Create a serializer with an appropriate context and use it to serialize
Create a serializer with an appropriate context and use it to serialize
the given comment, returning the result.
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
return
CommentSerializer
(
comment
,
context
=
context
)
.
data
def
test_basic
(
self
):
def
test_basic
(
self
):
...
...
lms/djangoapps/discussion_api/tests/test_views.py
View file @
09b00df7
...
@@ -158,6 +158,9 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
...
@@ -158,6 +158,9 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
"vote_count"
:
4
,
"vote_count"
:
4
,
"comment_count"
:
5
,
"comment_count"
:
5
,
"unread_comment_count"
:
3
,
"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
)
self
.
register_get_threads_response
(
source_threads
,
page
=
1
,
num_pages
=
2
)
response
=
self
.
client
.
get
(
self
.
url
,
{
"course_id"
:
unicode
(
self
.
course
.
id
)})
response
=
self
.
client
.
get
(
self
.
url
,
{
"course_id"
:
unicode
(
self
.
course
.
id
)})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment