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
4ea70aeb
Commit
4ea70aeb
authored
Nov 10, 2015
by
wajeeha-khalid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MA-862; accept application/merge-patch+json for comment/thread update
parent
685572cb
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
45 additions
and
7 deletions
+45
-7
common/djangoapps/util/testing.py
+18
-0
lms/djangoapps/discussion_api/tests/test_views.py
+10
-7
lms/djangoapps/discussion_api/views.py
+17
-0
No files found.
common/djangoapps/util/testing.py
View file @
4ea70aeb
"""
Utility Mixins for unit tests
"""
import
json
import
sys
import
sys
from
mock
import
patch
from
mock
import
patch
...
@@ -90,3 +95,16 @@ class EventTestMixin(object):
...
@@ -90,3 +95,16 @@ class EventTestMixin(object):
Reset the mock tracker in order to forget about old events.
Reset the mock tracker in order to forget about old events.
"""
"""
self
.
mock_tracker
.
reset_mock
()
self
.
mock_tracker
.
reset_mock
()
class
PatchMediaTypeMixin
(
object
):
"""
Generic mixin for verifying unsupported media type in PATCH
"""
def
test_patch_unsupported_media_type
(
self
):
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
self
.
url
,
json
.
dumps
({}),
content_type
=
self
.
unsupported_media_type
)
self
.
assertEqual
(
response
.
status_code
,
415
)
lms/djangoapps/discussion_api/tests/test_views.py
View file @
4ea70aeb
...
@@ -11,6 +11,7 @@ import mock
...
@@ -11,6 +11,7 @@ import mock
from
pytz
import
UTC
from
pytz
import
UTC
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
rest_framework.parsers
import
JSONParser
from
rest_framework.test
import
APIClient
from
rest_framework.test
import
APIClient
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore
import
ModuleStoreEnum
...
@@ -24,7 +25,7 @@ from discussion_api.tests.utils import (
...
@@ -24,7 +25,7 @@ from discussion_api.tests.utils import (
make_minimal_cs_thread
,
make_minimal_cs_thread
,
)
)
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
util.testing
import
UrlResetMixin
from
util.testing
import
UrlResetMixin
,
PatchMediaTypeMixin
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
check_mongo_calls
,
ItemFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
check_mongo_calls
,
ItemFactory
...
@@ -536,9 +537,10 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
...
@@ -536,9 +537,10 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@httpretty.activate
@httpretty.activate
@disable_signal
(
api
,
'thread_edited'
)
@disable_signal
(
api
,
'thread_edited'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
ThreadViewSetPartialUpdateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
class
ThreadViewSetPartialUpdateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
,
PatchMediaTypeMixin
):
"""Tests for ThreadViewSet partial_update"""
"""Tests for ThreadViewSet partial_update"""
def
setUp
(
self
):
def
setUp
(
self
):
self
.
unsupported_media_type
=
JSONParser
.
media_type
super
(
ThreadViewSetPartialUpdateTest
,
self
)
.
setUp
()
super
(
ThreadViewSetPartialUpdateTest
,
self
)
.
setUp
()
self
.
url
=
reverse
(
"thread-detail"
,
kwargs
=
{
"thread_id"
:
"test_thread"
})
self
.
url
=
reverse
(
"thread-detail"
,
kwargs
=
{
"thread_id"
:
"test_thread"
})
...
@@ -592,7 +594,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
...
@@ -592,7 +594,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
self
.
url
,
self
.
url
,
json
.
dumps
(
request_data
),
json
.
dumps
(
request_data
),
content_type
=
"application/json"
content_type
=
"application/
merge-patch+
json"
)
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
response_data
=
json
.
loads
(
response
.
content
)
response_data
=
json
.
loads
(
response
.
content
)
...
@@ -625,7 +627,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
...
@@ -625,7 +627,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
self
.
url
,
self
.
url
,
json
.
dumps
(
request_data
),
json
.
dumps
(
request_data
),
content_type
=
"application/json"
content_type
=
"application/
merge-patch+
json"
)
)
expected_response_data
=
{
expected_response_data
=
{
"field_errors"
:
{
"title"
:
{
"developer_message"
:
"This field may not be blank."
}}
"field_errors"
:
{
"title"
:
{
"developer_message"
:
"This field may not be blank."
}}
...
@@ -930,9 +932,10 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
...
@@ -930,9 +932,10 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
@disable_signal
(
api
,
'comment_edited'
)
@disable_signal
(
api
,
'comment_edited'
)
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
@mock.patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
class
CommentViewSetPartialUpdateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
):
class
CommentViewSetPartialUpdateTest
(
DiscussionAPIViewTestMixin
,
ModuleStoreTestCase
,
PatchMediaTypeMixin
):
"""Tests for CommentViewSet partial_update"""
"""Tests for CommentViewSet partial_update"""
def
setUp
(
self
):
def
setUp
(
self
):
self
.
unsupported_media_type
=
JSONParser
.
media_type
super
(
CommentViewSetPartialUpdateTest
,
self
)
.
setUp
()
super
(
CommentViewSetPartialUpdateTest
,
self
)
.
setUp
()
httpretty
.
reset
()
httpretty
.
reset
()
httpretty
.
enable
()
httpretty
.
enable
()
...
@@ -982,7 +985,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes
...
@@ -982,7 +985,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
self
.
url
,
self
.
url
,
json
.
dumps
(
request_data
),
json
.
dumps
(
request_data
),
content_type
=
"application/json"
content_type
=
"application/
merge-patch+
json"
)
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
response_data
=
json
.
loads
(
response
.
content
)
response_data
=
json
.
loads
(
response
.
content
)
...
@@ -1004,7 +1007,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes
...
@@ -1004,7 +1007,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
response
=
self
.
client
.
patch
(
# pylint: disable=no-member
self
.
url
,
self
.
url
,
json
.
dumps
(
request_data
),
json
.
dumps
(
request_data
),
content_type
=
"application/json"
content_type
=
"application/
merge-patch+
json"
)
)
expected_response_data
=
{
expected_response_data
=
{
"field_errors"
:
{
"raw_body"
:
{
"developer_message"
:
"This field may not be blank."
}}
"field_errors"
:
{
"raw_body"
:
{
"developer_message"
:
"This field may not be blank."
}}
...
...
lms/djangoapps/discussion_api/views.py
View file @
4ea70aeb
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
Discussion API views
Discussion API views
"""
"""
from
django.core.exceptions
import
ValidationError
from
django.core.exceptions
import
ValidationError
from
rest_framework.exceptions
import
UnsupportedMediaType
from
rest_framework.parsers
import
JSONParser
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
rest_framework.views
import
APIView
from
rest_framework.views
import
APIView
...
@@ -25,6 +27,7 @@ from discussion_api.api import (
...
@@ -25,6 +27,7 @@ from discussion_api.api import (
update_thread
,
update_thread
,
)
)
from
discussion_api.forms
import
CommentListGetForm
,
ThreadListGetForm
,
_PaginationForm
from
discussion_api.forms
import
CommentListGetForm
,
ThreadListGetForm
,
_PaginationForm
from
openedx.core.lib.api.parsers
import
MergePatchParser
from
openedx.core.lib.api.view_utils
import
DeveloperErrorViewMixin
,
view_auth_classes
from
openedx.core.lib.api.view_utils
import
DeveloperErrorViewMixin
,
view_auth_classes
...
@@ -119,6 +122,7 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -119,6 +122,7 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
PATCH /api/discussion/v1/threads/thread_id
PATCH /api/discussion/v1/threads/thread_id
{"raw_body": "Edited text"}
{"raw_body": "Edited text"}
Content Type: "application/merge-patch+json"
DELETE /api/discussion/v1/threads/thread_id
DELETE /api/discussion/v1/threads/thread_id
...
@@ -175,6 +179,9 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -175,6 +179,9 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
topic_id, type, title, and raw_body are accepted with the same meaning
topic_id, type, title, and raw_body are accepted with the same meaning
as in a POST request
as in a POST request
If "application/merge-patch+json" is not the specified content type,
a 415 error is returned.
**GET Response Values**:
**GET Response Values**:
* results: The list of threads; each item in the list has the same
* results: The list of threads; each item in the list has the same
...
@@ -232,6 +239,7 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -232,6 +239,7 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
"""
"""
lookup_field
=
"thread_id"
lookup_field
=
"thread_id"
parser_classes
=
(
JSONParser
,
MergePatchParser
,)
def
list
(
self
,
request
):
def
list
(
self
,
request
):
"""
"""
...
@@ -274,6 +282,8 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -274,6 +282,8 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
Implements the PATCH method for the instance endpoint as described in
Implements the PATCH method for the instance endpoint as described in
the class docstring.
the class docstring.
"""
"""
if
request
.
content_type
!=
MergePatchParser
.
media_type
:
raise
UnsupportedMediaType
(
request
.
content_type
)
return
Response
(
update_thread
(
request
,
thread_id
,
request
.
data
))
return
Response
(
update_thread
(
request
,
thread_id
,
request
.
data
))
def
destroy
(
self
,
request
,
thread_id
):
def
destroy
(
self
,
request
,
thread_id
):
...
@@ -307,6 +317,7 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -307,6 +317,7 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
PATCH /api/discussion/v1/comments/comment_id
PATCH /api/discussion/v1/comments/comment_id
{"raw_body": "Edited text"}
{"raw_body": "Edited text"}
Content Type: "application/merge-patch+json"
DELETE /api/discussion/v1/comments/comment_id
DELETE /api/discussion/v1/comments/comment_id
...
@@ -347,6 +358,9 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -347,6 +358,9 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
raw_body is accepted with the same meaning as in a POST request
raw_body is accepted with the same meaning as in a POST request
If "application/merge-patch+json" is not the specified content type,
a 415 error is returned.
**GET Response Values**:
**GET Response Values**:
* results: The list of comments; each item in the list has the same
* results: The list of comments; each item in the list has the same
...
@@ -409,6 +423,7 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -409,6 +423,7 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
"""
"""
lookup_field
=
"comment_id"
lookup_field
=
"comment_id"
parser_classes
=
(
JSONParser
,
MergePatchParser
,)
def
list
(
self
,
request
):
def
list
(
self
,
request
):
"""
"""
...
@@ -465,4 +480,6 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
...
@@ -465,4 +480,6 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
Implements the PATCH method for the instance endpoint as described in
Implements the PATCH method for the instance endpoint as described in
the class docstring.
the class docstring.
"""
"""
if
request
.
content_type
!=
MergePatchParser
.
media_type
:
raise
UnsupportedMediaType
(
request
.
content_type
)
return
Response
(
update_comment
(
request
,
comment_id
,
request
.
data
))
return
Response
(
update_comment
(
request
,
comment_id
,
request
.
data
))
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