feat: reapply forum v2 changes (#36002)

* feat: Reapply "Integrate Forum V2 into edx-platform"

This reverts commit 818aa343a2.

* feat: make it possible to globally disable forum v2 with setting

We introduce a setting that allows us to bypass any course waffle flag
check. The advantage of such a setting is that we don't need to find the
course ID: in some cases, we might not have access to the course ID, and
we need to look for it... in forum v2.

See discussion here: https://github.com/openedx/forum/issues/137

* chore: bump openedx-forum to 0.1.5

This should fix an issue with index creation on edX.org.
This commit is contained in:
Régis Behmo
2024-12-12 08:18:33 +01:00
committed by GitHub
parent f96f92677f
commit 065adf398e
26 changed files with 1895 additions and 426 deletions

View File

@@ -82,6 +82,7 @@ class MockRequestSetupMixin:
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
class CreateThreadGroupIdTestCase(
MockRequestSetupMixin,
CohortedTestCase,
@@ -90,7 +91,21 @@ class CreateThreadGroupIdTestCase(
):
cs_endpoint = "/threads"
def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True):
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
def call_view(self, mock_is_forum_v2_enabled, mock_request, commentable_id, user, group_id, pass_group_id=True):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {})
request_data = {"body": "body", "title": "title", "thread_type": "discussion"}
if pass_group_id:
@@ -105,8 +120,9 @@ class CreateThreadGroupIdTestCase(
commentable_id=commentable_id
)
def test_group_info_in_response(self, mock_request):
def test_group_info_in_response(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.student,
@@ -116,6 +132,7 @@ class CreateThreadGroupIdTestCase(
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
@disable_signal(views, 'thread_edited')
@disable_signal(views, 'thread_voted')
@disable_signal(views, 'thread_deleted')
@@ -127,11 +144,18 @@ class ThreadActionGroupIdTestCase(
def call_view(
self,
view_name,
mock_is_forum_v2_enabled,
mock_request,
user=None,
post_params=None,
view_args=None
):
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(
mock_request,
{
@@ -154,53 +178,58 @@ class ThreadActionGroupIdTestCase(
**(view_args or {})
)
def test_update(self, mock_request):
def test_update(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
"update_thread",
mock_is_forum_v2_enabled,
mock_request,
post_params={"body": "body", "title": "title"}
)
self._assert_json_response_contains_group_info(response)
def test_delete(self, mock_request):
response = self.call_view("delete_thread", mock_request)
def test_delete(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view("delete_thread", mock_is_forum_v2_enabled, mock_request)
self._assert_json_response_contains_group_info(response)
def test_vote(self, mock_request):
def test_vote(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
"vote_for_thread",
mock_is_forum_v2_enabled,
mock_request,
view_args={"value": "up"}
)
self._assert_json_response_contains_group_info(response)
response = self.call_view("undo_vote_for_thread", mock_request)
response = self.call_view("undo_vote_for_thread", mock_is_forum_v2_enabled, mock_request)
self._assert_json_response_contains_group_info(response)
def test_flag(self, mock_request):
def test_flag(self, mock_is_forum_v2_enabled, mock_request):
with mock.patch('openedx.core.djangoapps.django_comment_common.signals.thread_flagged.send') as signal_mock:
response = self.call_view("flag_abuse_for_thread", mock_request)
response = self.call_view("flag_abuse_for_thread", mock_is_forum_v2_enabled, mock_request)
self._assert_json_response_contains_group_info(response)
self.assertEqual(signal_mock.call_count, 1)
response = self.call_view("un_flag_abuse_for_thread", mock_request)
response = self.call_view("un_flag_abuse_for_thread", mock_is_forum_v2_enabled, mock_request)
self._assert_json_response_contains_group_info(response)
def test_pin(self, mock_request):
def test_pin(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
"pin_thread",
mock_is_forum_v2_enabled,
mock_request,
user=self.moderator
)
self._assert_json_response_contains_group_info(response)
response = self.call_view(
"un_pin_thread",
mock_is_forum_v2_enabled,
mock_request,
user=self.moderator
)
self._assert_json_response_contains_group_info(response)
def test_openclose(self, mock_request):
def test_openclose(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
"openclose_thread",
mock_is_forum_v2_enabled,
mock_request,
user=self.moderator
)
@@ -280,10 +309,11 @@ class ViewsTestCaseMixin:
data["depth"] = 0
self._set_mock_request_data(mock_request, data)
def create_thread_helper(self, mock_request, extra_request_data=None, extra_response_data=None):
def create_thread_helper(self, mock_is_forum_v2_enabled, mock_request, extra_request_data=None, extra_response_data=None):
"""
Issues a request to create a thread and verifies the result.
"""
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"thread_type": "discussion",
"title": "Hello",
@@ -350,10 +380,11 @@ class ViewsTestCaseMixin:
)
assert response.status_code == 200
def update_thread_helper(self, mock_request):
def update_thread_helper(self, mock_is_forum_v2_enabled, mock_request):
"""
Issues a request to update a thread and verifies the result.
"""
mock_is_forum_v2_enabled.return_value = False
self._setup_mock_request(mock_request)
# Mock out saving in order to test that content is correctly
# updated. Otherwise, the call to thread.save() receives the
@@ -376,6 +407,7 @@ class ViewsTestCaseMixin:
@ddt.ddt
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
@disable_signal(views, 'thread_created')
@disable_signal(views, 'thread_edited')
class ViewsQueryCountTestCase(
@@ -393,6 +425,11 @@ class ViewsQueryCountTestCase(
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def count_queries(func): # pylint: disable=no-self-argument
"""
@@ -414,22 +451,23 @@ class ViewsQueryCountTestCase(
)
@ddt.unpack
@count_queries
def test_create_thread(self, mock_request):
self.create_thread_helper(mock_request)
def test_create_thread(self, mock_is_forum_v2_enabled, mock_request):
self.create_thread_helper(mock_is_forum_v2_enabled, mock_request)
@ddt.data(
(ModuleStoreEnum.Type.split, 3, 6, 41),
)
@ddt.unpack
@count_queries
def test_update_thread(self, mock_request):
self.update_thread_helper(mock_request)
def test_update_thread(self, mock_is_forum_v2_enabled, mock_request):
self.update_thread_helper(mock_is_forum_v2_enabled, mock_request)
@ddt.ddt
@disable_signal(views, 'comment_flagged')
@disable_signal(views, 'thread_flagged')
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
class ViewsTestCase(
ForumsEnableMixin,
UrlResetMixin,
@@ -464,7 +502,16 @@ class ViewsTestCase(
# so we need to call super.setUp() which reloads urls.py (because
# of the UrlResetMixin)
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
# Patch the comment client user save method so it does not try
# to create a new cc user when creating a django user
with patch('common.djangoapps.student.models.user.cc.User.save'):
@@ -497,11 +544,11 @@ class ViewsTestCase(
with self.assert_signal_sent(views, signal, sender=None, user=user, exclude_args=('post',)):
yield
def test_create_thread(self, mock_request):
def test_create_thread(self, mock_is_forum_v2_enabled, mock_request):
with self.assert_discussion_signals('thread_created'):
self.create_thread_helper(mock_request)
self.create_thread_helper(mock_is_forum_v2_enabled, mock_request)
def test_create_thread_standalone(self, mock_request):
def test_create_thread_standalone(self, mock_is_forum_v2_enabled, mock_request):
team = CourseTeamFactory.create(
name="A Team",
course_id=self.course_id,
@@ -513,15 +560,15 @@ class ViewsTestCase(
team.add_user(self.student)
# create_thread_helper verifies that extra data are passed through to the comments service
self.create_thread_helper(mock_request, extra_response_data={'context': ThreadContext.STANDALONE})
self.create_thread_helper(mock_is_forum_v2_enabled, mock_request, extra_response_data={'context': ThreadContext.STANDALONE})
@ddt.data(
('follow_thread', 'thread_followed'),
('unfollow_thread', 'thread_unfollowed'),
)
@ddt.unpack
def test_follow_unfollow_thread_signals(self, view_name, signal, mock_request):
self.create_thread_helper(mock_request)
def test_follow_unfollow_thread_signals(self, view_name, signal, mock_is_forum_v2_enabled, mock_request):
self.create_thread_helper(mock_is_forum_v2_enabled, mock_request)
with self.assert_discussion_signals(signal):
response = self.client.post(
@@ -532,7 +579,8 @@ class ViewsTestCase(
)
assert response.status_code == 200
def test_delete_thread(self, mock_request):
def test_delete_thread(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"user_id": str(self.student.id),
"closed": False,
@@ -551,7 +599,8 @@ class ViewsTestCase(
assert response.status_code == 200
assert mock_request.called
def test_delete_comment(self, mock_request):
def test_delete_comment(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"user_id": str(self.student.id),
"closed": False,
@@ -573,12 +622,13 @@ class ViewsTestCase(
assert args[0] == 'delete'
assert args[1].endswith(f"/{test_comment_id}")
def _test_request_error(self, view_name, view_kwargs, data, mock_request):
def _test_request_error(self, view_name, view_kwargs, data, mock_is_forum_v2_enabled, mock_request):
"""
Submit a request against the given view with the given data and ensure
that the result is a 400 error and that no data was posted using
mock_request
"""
mock_is_forum_v2_enabled.return_value = False
self._setup_mock_request(mock_request, include_depth=(view_name == "create_sub_comment"))
response = self.client.post(reverse(view_name, kwargs=view_kwargs), data=data)
@@ -586,87 +636,97 @@ class ViewsTestCase(
for call in mock_request.call_args_list:
assert call[0][0].lower() == 'get'
def test_create_thread_no_title(self, mock_request):
def test_create_thread_no_title(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_thread",
{"commentable_id": "dummy", "course_id": str(self.course_id)},
{"body": "foo"},
mock_is_forum_v2_enabled,
mock_request
)
def test_create_thread_empty_title(self, mock_request):
def test_create_thread_empty_title(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_thread",
{"commentable_id": "dummy", "course_id": str(self.course_id)},
{"body": "foo", "title": " "},
mock_is_forum_v2_enabled,
mock_request
)
def test_create_thread_no_body(self, mock_request):
def test_create_thread_no_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_thread",
{"commentable_id": "dummy", "course_id": str(self.course_id)},
{"title": "foo"},
mock_is_forum_v2_enabled,
mock_request
)
def test_create_thread_empty_body(self, mock_request):
def test_create_thread_empty_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_thread",
{"commentable_id": "dummy", "course_id": str(self.course_id)},
{"body": " ", "title": "foo"},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_thread_no_title(self, mock_request):
def test_update_thread_no_title(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"update_thread",
{"thread_id": "dummy", "course_id": str(self.course_id)},
{"body": "foo"},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_thread_empty_title(self, mock_request):
def test_update_thread_empty_title(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"update_thread",
{"thread_id": "dummy", "course_id": str(self.course_id)},
{"body": "foo", "title": " "},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_thread_no_body(self, mock_request):
def test_update_thread_no_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"update_thread",
{"thread_id": "dummy", "course_id": str(self.course_id)},
{"title": "foo"},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_thread_empty_body(self, mock_request):
def test_update_thread_empty_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"update_thread",
{"thread_id": "dummy", "course_id": str(self.course_id)},
{"body": " ", "title": "foo"},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_thread_course_topic(self, mock_request):
def test_update_thread_course_topic(self, mock_is_forum_v2_enabled, mock_request):
with self.assert_discussion_signals('thread_edited'):
self.update_thread_helper(mock_request)
self.update_thread_helper(mock_is_forum_v2_enabled, mock_request)
@patch(
'lms.djangoapps.discussion.django_comment_client.utils.get_discussion_categories_ids',
return_value=["test_commentable"],
)
def test_update_thread_wrong_commentable_id(self, mock_get_discussion_id_map, mock_request):
def test_update_thread_wrong_commentable_id(self, mock_get_discussion_id_map, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"update_thread",
{"thread_id": "dummy", "course_id": str(self.course_id)},
{"body": "foo", "title": "foo", "commentable_id": "wrong_commentable"},
mock_is_forum_v2_enabled,
mock_request
)
def test_create_comment(self, mock_request):
def test_create_comment(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._setup_mock_request(mock_request)
with self.assert_discussion_signals('comment_created'):
response = self.client.post(
@@ -678,55 +738,62 @@ class ViewsTestCase(
)
assert response.status_code == 200
def test_create_comment_no_body(self, mock_request):
def test_create_comment_no_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_comment",
{"thread_id": "dummy", "course_id": str(self.course_id)},
{},
mock_is_forum_v2_enabled,
mock_request
)
def test_create_comment_empty_body(self, mock_request):
def test_create_comment_empty_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_comment",
{"thread_id": "dummy", "course_id": str(self.course_id)},
{"body": " "},
mock_is_forum_v2_enabled,
mock_request
)
def test_create_sub_comment_no_body(self, mock_request):
def test_create_sub_comment_no_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_sub_comment",
{"comment_id": "dummy", "course_id": str(self.course_id)},
{},
mock_is_forum_v2_enabled,
mock_request
)
def test_create_sub_comment_empty_body(self, mock_request):
def test_create_sub_comment_empty_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"create_sub_comment",
{"comment_id": "dummy", "course_id": str(self.course_id)},
{"body": " "},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_comment_no_body(self, mock_request):
def test_update_comment_no_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"update_comment",
{"comment_id": "dummy", "course_id": str(self.course_id)},
{},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_comment_empty_body(self, mock_request):
def test_update_comment_empty_body(self, mock_is_forum_v2_enabled, mock_request):
self._test_request_error(
"update_comment",
{"comment_id": "dummy", "course_id": str(self.course_id)},
{"body": " "},
mock_is_forum_v2_enabled,
mock_request
)
def test_update_comment_basic(self, mock_request):
def test_update_comment_basic(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._setup_mock_request(mock_request)
comment_id = "test_comment_id"
updated_body = "updated body"
@@ -748,13 +815,14 @@ class ViewsTestCase(
data={"body": updated_body}
)
def test_flag_thread_open(self, mock_request):
self.flag_thread(mock_request, False)
def test_flag_thread_open(self, mock_is_forum_v2_enabled, mock_request):
self.flag_thread(mock_is_forum_v2_enabled, mock_request, False)
def test_flag_thread_close(self, mock_request):
self.flag_thread(mock_request, True)
def test_flag_thread_close(self, mock_is_forum_v2_enabled, mock_request):
self.flag_thread(mock_is_forum_v2_enabled, mock_request, True)
def flag_thread(self, mock_request, is_closed):
def flag_thread(self, mock_is_forum_v2_enabled, mock_request, is_closed):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"title": "Hello",
"body": "this is a post",
@@ -826,13 +894,14 @@ class ViewsTestCase(
assert response.status_code == 200
def test_un_flag_thread_open(self, mock_request):
self.un_flag_thread(mock_request, False)
def test_un_flag_thread_open(self, mock_is_forum_v2_enabled, mock_request):
self.un_flag_thread(mock_is_forum_v2_enabled, mock_request, False)
def test_un_flag_thread_close(self, mock_request):
self.un_flag_thread(mock_request, True)
def test_un_flag_thread_close(self, mock_is_forum_v2_enabled, mock_request):
self.un_flag_thread(mock_is_forum_v2_enabled, mock_request, True)
def un_flag_thread(self, mock_request, is_closed):
def un_flag_thread(self, mock_is_forum_v2_enabled, mock_request, is_closed):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"title": "Hello",
"body": "this is a post",
@@ -905,13 +974,14 @@ class ViewsTestCase(
assert response.status_code == 200
def test_flag_comment_open(self, mock_request):
self.flag_comment(mock_request, False)
def test_flag_comment_open(self, mock_is_forum_v2_enabled, mock_request):
self.flag_comment(mock_is_forum_v2_enabled, mock_request, False)
def test_flag_comment_close(self, mock_request):
self.flag_comment(mock_request, True)
def test_flag_comment_close(self, mock_is_forum_v2_enabled, mock_request):
self.flag_comment(mock_is_forum_v2_enabled, mock_request, True)
def flag_comment(self, mock_request, is_closed):
def flag_comment(self, mock_is_forum_v2_enabled, mock_request, is_closed):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"body": "this is a comment",
"course_id": "MITx/999/Robot_Super_Course",
@@ -976,13 +1046,14 @@ class ViewsTestCase(
assert response.status_code == 200
def test_un_flag_comment_open(self, mock_request):
self.un_flag_comment(mock_request, False)
def test_un_flag_comment_open(self, mock_is_forum_v2_enabled, mock_request):
self.un_flag_comment(mock_is_forum_v2_enabled, mock_request, False)
def test_un_flag_comment_close(self, mock_request):
self.un_flag_comment(mock_request, True)
def test_un_flag_comment_close(self, mock_is_forum_v2_enabled, mock_request):
self.un_flag_comment(mock_is_forum_v2_enabled, mock_request, True)
def un_flag_comment(self, mock_request, is_closed):
def un_flag_comment(self, mock_is_forum_v2_enabled, mock_request, is_closed):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"body": "this is a comment",
"course_id": "MITx/999/Robot_Super_Course",
@@ -1054,7 +1125,8 @@ class ViewsTestCase(
('downvote_comment', 'comment_id', 'comment_voted')
)
@ddt.unpack
def test_voting(self, view_name, item_id, signal, mock_request):
def test_voting(self, view_name, item_id, signal, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._setup_mock_request(mock_request)
with self.assert_discussion_signals(signal):
response = self.client.post(
@@ -1065,7 +1137,8 @@ class ViewsTestCase(
)
assert response.status_code == 200
def test_endorse_comment(self, mock_request):
def test_endorse_comment(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._setup_mock_request(mock_request)
self.client.login(username=self.moderator.username, password=self.password)
with self.assert_discussion_signals('comment_endorsed', user=self.moderator):
@@ -1079,6 +1152,7 @@ class ViewsTestCase(
@patch("openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request", autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
@disable_signal(views, 'comment_endorsed')
class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase, MockRequestSetupMixin):
@@ -1106,8 +1180,19 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def test_pin_thread_as_student(self, mock_request):
def test_pin_thread_as_student(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {})
self.client.login(username=self.student.username, password=self.password)
response = self.client.post(
@@ -1115,7 +1200,8 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
)
assert response.status_code == 401
def test_pin_thread_as_moderator(self, mock_request):
def test_pin_thread_as_moderator(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {})
self.client.login(username=self.moderator.username, password=self.password)
response = self.client.post(
@@ -1123,7 +1209,8 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
)
assert response.status_code == 200
def test_un_pin_thread_as_student(self, mock_request):
def test_un_pin_thread_as_student(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {})
self.client.login(username=self.student.username, password=self.password)
response = self.client.post(
@@ -1131,7 +1218,8 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
)
assert response.status_code == 401
def test_un_pin_thread_as_moderator(self, mock_request):
def test_un_pin_thread_as_moderator(self, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {})
self.client.login(username=self.moderator.username, password=self.password)
response = self.client.post(
@@ -1139,7 +1227,7 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
)
assert response.status_code == 200
def _set_mock_request_thread_and_comment(self, mock_request, thread_data, comment_data):
def _set_mock_request_thread_and_comment(self, mock_is_forum_v2_enabled, mock_request, thread_data, comment_data):
def handle_request(*args, **kwargs):
url = args[1]
if "/threads/" in url:
@@ -1148,10 +1236,12 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
return self._create_response_mock(comment_data)
else:
raise ArgumentError("Bad url to mock request")
mock_is_forum_v2_enabled.return_value = False
mock_request.side_effect = handle_request
def test_endorse_response_as_staff(self, mock_request):
def test_endorse_response_as_staff(self, mock_is_forum_v2_enabled, mock_request):
self._set_mock_request_thread_and_comment(
mock_is_forum_v2_enabled,
mock_request,
{"type": "thread", "thread_type": "question", "user_id": str(self.student.id), "commentable_id": "course"},
{"type": "comment", "thread_id": "dummy"}
@@ -1162,8 +1252,9 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
)
assert response.status_code == 200
def test_endorse_response_as_student(self, mock_request):
def test_endorse_response_as_student(self, mock_is_forum_v2_enabled, mock_request):
self._set_mock_request_thread_and_comment(
mock_is_forum_v2_enabled,
mock_request,
{"type": "thread", "thread_type": "question",
"user_id": str(self.moderator.id), "commentable_id": "course"},
@@ -1175,8 +1266,9 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor
)
assert response.status_code == 401
def test_endorse_response_as_student_question_author(self, mock_request):
def test_endorse_response_as_student_question_author(self, mock_is_forum_v2_enabled, mock_request):
self._set_mock_request_thread_and_comment(
mock_is_forum_v2_enabled,
mock_request,
{"type": "thread", "thread_type": "question", "user_id": str(self.student.id), "commentable_id": "course"},
{"type": "comment", "thread_id": "dummy"}
@@ -1209,10 +1301,12 @@ class CreateThreadUnicodeTestCase(
CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id)
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def _test_unicode_data(self, text, mock_request,):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def _test_unicode_data(self, text, mock_is_forum_v2_enabled, mock_request,):
"""
Test to make sure unicode data in a thread doesn't break it.
"""
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {})
request = RequestFactory().post("dummy_url", {"thread_type": "discussion", "body": text, "title": text})
request.user = self.student
@@ -1235,6 +1329,13 @@ class UpdateThreadUnicodeTestCase(
UnicodeTestMixin,
MockRequestSetupMixin
):
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
@classmethod
def setUpClass(cls):
@@ -1255,7 +1356,9 @@ class UpdateThreadUnicodeTestCase(
return_value=["test_commentable"],
)
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def _test_unicode_data(self, text, mock_request, mock_get_discussion_id_map):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def _test_unicode_data(self, text, mock_is_forum_v2_enabled, mock_request, mock_get_discussion_id_map):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"user_id": str(self.student.id),
"closed": False,
@@ -1280,6 +1383,13 @@ class CreateCommentUnicodeTestCase(
UnicodeTestMixin,
MockRequestSetupMixin
):
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
@classmethod
def setUpClass(cls):
@@ -1296,7 +1406,9 @@ class CreateCommentUnicodeTestCase(
CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id)
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def _test_unicode_data(self, text, mock_request):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def _test_unicode_data(self, text, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
commentable_id = "non_team_dummy_id"
self._set_mock_request_data(mock_request, {
"closed": False,
@@ -1327,6 +1439,13 @@ class UpdateCommentUnicodeTestCase(
UnicodeTestMixin,
MockRequestSetupMixin
):
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
@classmethod
def setUpClass(cls):
@@ -1343,7 +1462,9 @@ class UpdateCommentUnicodeTestCase(
CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id)
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def _test_unicode_data(self, text, mock_request):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def _test_unicode_data(self, text, mock_is_forum_v2_enabled, mock_request):
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"user_id": str(self.student.id),
"closed": False,
@@ -1359,6 +1480,7 @@ class UpdateCommentUnicodeTestCase(
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
class CommentActionTestCase(
MockRequestSetupMixin,
CohortedTestCase,
@@ -1367,11 +1489,18 @@ class CommentActionTestCase(
def call_view(
self,
view_name,
mock_is_forum_v2_enabled,
mock_request,
user=None,
post_params=None,
view_args=None
):
mock_is_forum_v2_enabled.return_value = False
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
self._set_mock_request_data(
mock_request,
{
@@ -1394,9 +1523,9 @@ class CommentActionTestCase(
**(view_args or {})
)
def test_flag(self, mock_request):
def test_flag(self, mock_is_forum_v2_enabled, mock_request):
with mock.patch('openedx.core.djangoapps.django_comment_common.signals.comment_flagged.send') as signal_mock:
self.call_view("flag_abuse_for_comment", mock_request)
self.call_view("flag_abuse_for_comment", mock_is_forum_v2_enabled, mock_request)
self.assertEqual(signal_mock.call_count, 1)
@@ -1410,6 +1539,14 @@ class CreateSubCommentUnicodeTestCase(
"""
Make sure comments under a response can handle unicode.
"""
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
@classmethod
def setUpClass(cls):
# pylint: disable=super-method-not-called
@@ -1425,10 +1562,12 @@ class CreateSubCommentUnicodeTestCase(
CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id)
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def _test_unicode_data(self, text, mock_request):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def _test_unicode_data(self, text, mock_is_forum_v2_enabled, mock_request):
"""
Create a comment with unicode in it.
"""
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"closed": False,
"depth": 1,
@@ -1453,6 +1592,7 @@ class CreateSubCommentUnicodeTestCase(
@ddt.ddt
@patch("openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request", autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
@disable_signal(views, 'thread_voted')
@disable_signal(views, 'thread_edited')
@disable_signal(views, 'comment_created')
@@ -1562,13 +1702,24 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
users=[cls.group_moderator, cls.cohorted]
)
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self):
super().setUp()
def _setup_mock(self, user, mock_request, data):
def _setup_mock(self, user, mock_is_forum_v2_enabled, mock_request, data):
user = getattr(self, user)
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, data)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.client.login(username=user.username, password=self.password)
@ddt.data(
@@ -1593,7 +1744,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
('group_moderator', 'cohorted', 'course_commentable_id', 401, CourseDiscussionSettings.NONE)
)
@ddt.unpack
def test_update_thread(self, user, thread_author, commentable_id, status_code, division_scheme, mock_request):
def test_update_thread(self, user, thread_author, commentable_id, status_code, division_scheme, mock_is_forum_v2_enabled, mock_request):
"""
Verify that update_thread is limited to thread authors and privileged users (team membership does not matter).
"""
@@ -1603,7 +1754,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
thread_author = getattr(self, thread_author)
self._setup_mock(
user, mock_request, # user is the person making the request.
user, mock_is_forum_v2_enabled, mock_request, # user is the person making the request.
{
"user_id": str(thread_author.id),
"closed": False, "commentable_id": commentable_id,
@@ -1643,12 +1794,12 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
('group_moderator', 'cohorted', 'team_commentable_id', 401, CourseDiscussionSettings.NONE)
)
@ddt.unpack
def test_delete_comment(self, user, comment_author, commentable_id, status_code, division_scheme, mock_request):
def test_delete_comment(self, user, comment_author, commentable_id, status_code, division_scheme, mock_is_forum_v2_enabled, mock_request):
commentable_id = getattr(self, commentable_id)
comment_author = getattr(self, comment_author)
self.change_divided_discussion_settings(division_scheme)
self._setup_mock(user, mock_request, {
self._setup_mock(user, mock_is_forum_v2_enabled, mock_request, {
"closed": False,
"commentable_id": commentable_id,
"user_id": str(comment_author.id),
@@ -1671,12 +1822,12 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
@ddt.data(*ddt_permissions_args)
@ddt.unpack
def test_create_comment(self, user, commentable_id, status_code, mock_request):
def test_create_comment(self, user, commentable_id, status_code, mock_is_forum_v2_enabled, mock_request):
"""
Verify that create_comment is limited to members of the team or users with 'edit_content' permission.
"""
commentable_id = getattr(self, commentable_id)
self._setup_mock(user, mock_request, {"closed": False, "commentable_id": commentable_id})
self._setup_mock(user, mock_is_forum_v2_enabled, mock_request, {"closed": False, "commentable_id": commentable_id})
response = self.client.post(
reverse(
@@ -1692,13 +1843,13 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
@ddt.data(*ddt_permissions_args)
@ddt.unpack
def test_create_sub_comment(self, user, commentable_id, status_code, mock_request):
def test_create_sub_comment(self, user, commentable_id, status_code, mock_is_forum_v2_enabled, mock_request):
"""
Verify that create_subcomment is limited to members of the team or users with 'edit_content' permission.
"""
commentable_id = getattr(self, commentable_id)
self._setup_mock(
user, mock_request,
user, mock_is_forum_v2_enabled, mock_request,
{"closed": False, "commentable_id": commentable_id, "thread_id": "dummy_thread"},
)
response = self.client.post(
@@ -1715,14 +1866,14 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
@ddt.data(*ddt_permissions_args)
@ddt.unpack
def test_comment_actions(self, user, commentable_id, status_code, mock_request):
def test_comment_actions(self, user, commentable_id, status_code, mock_is_forum_v2_enabled, mock_request):
"""
Verify that voting and flagging of comments is limited to members of the team or users with
'edit_content' permission.
"""
commentable_id = getattr(self, commentable_id)
self._setup_mock(
user, mock_request,
user, mock_is_forum_v2_enabled, mock_request,
{
"closed": False,
"commentable_id": commentable_id,
@@ -1742,14 +1893,14 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto
@ddt.data(*ddt_permissions_args)
@ddt.unpack
def test_threads_actions(self, user, commentable_id, status_code, mock_request):
def test_threads_actions(self, user, commentable_id, status_code, mock_is_forum_v2_enabled, mock_request):
"""
Verify that voting, flagging, and following of threads is limited to members of the team or users with
'edit_content' permission.
"""
commentable_id = getattr(self, commentable_id)
self._setup_mock(
user, mock_request,
user, mock_is_forum_v2_enabled, mock_request,
{"closed": False, "commentable_id": commentable_id, "body": "dummy body", "course_id": str(self.course.id)}
)
for action in ["upvote_thread", "downvote_thread", "un_flag_abuse_for_thread", "flag_abuse_for_thread",
@@ -1772,6 +1923,19 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
"""
Forum actions are expected to launch analytics events. Test these here.
"""
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
@classmethod
def setUpClass(cls):
# pylint: disable=super-method-not-called
@@ -1791,12 +1955,14 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
@patch('eventtracking.tracker.emit')
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def test_response_event(self, mock_request, mock_emit):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def test_response_event(self, mock_is_forum_v2_enabled, mock_request, mock_emit):
"""
Check to make sure an event is fired when a user responds to a thread.
"""
event_receiver = Mock()
FORUM_THREAD_RESPONSE_CREATED.connect(event_receiver)
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"closed": False,
"commentable_id": 'test_commentable_id',
@@ -1833,12 +1999,14 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
@patch('eventtracking.tracker.emit')
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def test_comment_event(self, mock_request, mock_emit):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def test_comment_event(self, mock_is_forum_v2_enabled, mock_request, mock_emit):
"""
Ensure an event is fired when someone comments on a response.
"""
event_receiver = Mock()
FORUM_RESPONSE_COMMENT_CREATED.connect(event_receiver)
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"closed": False,
"depth": 1,
@@ -1875,6 +2043,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
@patch('eventtracking.tracker.emit')
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
@ddt.data((
'create_thread',
'edx.forum.thread.created', {
@@ -1896,7 +2065,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
{'comment_id': 'dummy_comment_id'}
))
@ddt.unpack
def test_team_events(self, view_name, event_name, view_data, view_kwargs, mock_request, mock_emit):
def test_team_events(self, view_name, event_name, view_data, view_kwargs, mock_is_forum_v2_enabled, mock_request, mock_emit):
user = self.student
team = CourseTeamFactory.create(discussion_topic_id=TEAM_COMMENTABLE_ID)
CourseTeamMembershipFactory.create(team=team, user=user)
@@ -1905,6 +2074,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
forum_event = views.TRACKING_LOG_TO_EVENT_MAPS.get(event_name)
forum_event.connect(event_receiver)
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
'closed': False,
'commentable_id': TEAM_COMMENTABLE_ID,
@@ -1943,9 +2113,11 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
@ddt.unpack
@patch('eventtracking.tracker.emit')
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def test_thread_voted_event(self, view_name, obj_id_name, obj_type, mock_request, mock_emit):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def test_thread_voted_event(self, view_name, obj_id_name, obj_type, mock_is_forum_v2_enabled, mock_request, mock_emit):
undo = view_name.startswith('undo')
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
'closed': False,
'commentable_id': 'test_commentable_id',
@@ -1971,11 +2143,13 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque
@ddt.data('follow_thread', 'unfollow_thread',)
@patch('eventtracking.tracker.emit')
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def test_thread_followed_event(self, view_name, mock_request, mock_emit):
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def test_thread_followed_event(self, view_name, mock_is_forum_v2_enabled, mock_request, mock_emit):
event_receiver = Mock()
for signal in views.TRACKING_LOG_TO_EVENT_MAPS.values():
signal.connect(event_receiver)
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
'closed': False,
'commentable_id': 'test_commentable_id',
@@ -2025,10 +2199,11 @@ class UsersEndpointTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockRe
cls.other_user = UserFactory.create(username="other")
CourseEnrollmentFactory(user=cls.other_user, course_id=cls.course.id)
def set_post_counts(self, mock_request, threads_count=1, comments_count=1):
def set_post_counts(self, mock_is_forum_v2_enabled, mock_request, threads_count=1, comments_count=1):
"""
sets up a mock response from the comments service for getting post counts for our other_user
"""
mock_is_forum_v2_enabled.return_value = False
self._set_mock_request_data(mock_request, {
"threads_count": threads_count,
"comments_count": comments_count,
@@ -2042,15 +2217,17 @@ class UsersEndpointTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockRe
return views.users(request, course_id=str(course_id))
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def test_finds_exact_match(self, mock_request):
self.set_post_counts(mock_request)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def test_finds_exact_match(self, mock_is_forum_v2_enabled, mock_request):
self.set_post_counts(mock_is_forum_v2_enabled, mock_request)
response = self.make_request(username="other")
assert response.status_code == 200
assert json.loads(response.content.decode('utf-8'))['users'] == [{'id': self.other_user.id, 'username': self.other_user.username}]
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def test_finds_no_match(self, mock_request):
self.set_post_counts(mock_request)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def test_finds_no_match(self, mock_is_forum_v2_enabled, mock_request):
self.set_post_counts(mock_is_forum_v2_enabled, mock_request)
response = self.make_request(username="othor")
assert response.status_code == 200
assert json.loads(response.content.decode('utf-8'))['users'] == []
@@ -2086,8 +2263,9 @@ class UsersEndpointTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockRe
assert 'users' not in content
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
def test_requires_matched_user_has_forum_content(self, mock_request):
self.set_post_counts(mock_request, 0, 0)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
def test_requires_matched_user_has_forum_content(self, mock_is_forum_v2_enabled, mock_request):
self.set_post_counts(mock_is_forum_v2_enabled, mock_request, 0, 0)
response = self.make_request(username="other")
assert response.status_code == 200
assert json.loads(response.content.decode('utf-8'))['users'] == []

View File

@@ -562,7 +562,6 @@ def create_thread(request, course_id, commentable_id):
params['context'] = ThreadContext.STANDALONE
else:
params['context'] = ThreadContext.COURSE
thread = cc.Thread(**params)
# Divide the thread if required

View File

@@ -60,51 +60,76 @@ class CohortedTopicGroupIdTestMixin(GroupIdAssertionMixin):
Provides test cases to verify that views pass the correct `group_id` to
the comments service when requesting content in cohorted discussions.
"""
def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True):
def call_view(self, mock_is_forum_v2_enabled, mock_request, commentable_id, user, group_id, pass_group_id=True):
"""
Call the view for the implementing test class, constructing a request
from the parameters.
"""
pass # lint-amnesty, pylint: disable=unnecessary-pass
def test_cohorted_topic_student_without_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.student, '', pass_group_id=False)
def test_cohorted_topic_student_without_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(mock_is_forum_v2_enabled, mock_request, "cohorted_topic", self.student, '', pass_group_id=False)
self._assert_comments_service_called_with_group_id(mock_request, self.student_cohort.id)
def test_cohorted_topic_student_none_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.student, "")
def test_cohorted_topic_student_none_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(mock_is_forum_v2_enabled, mock_request, "cohorted_topic", self.student, "")
self._assert_comments_service_called_with_group_id(mock_request, self.student_cohort.id)
def test_cohorted_topic_student_with_own_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.student, self.student_cohort.id)
def test_cohorted_topic_student_with_own_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(mock_is_forum_v2_enabled, mock_request, "cohorted_topic", self.student, self.student_cohort.id)
self._assert_comments_service_called_with_group_id(mock_request, self.student_cohort.id)
def test_cohorted_topic_student_with_other_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.student, self.moderator_cohort.id)
def test_cohorted_topic_student_with_other_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.student,
self.moderator_cohort.id
)
self._assert_comments_service_called_with_group_id(mock_request, self.student_cohort.id)
def test_cohorted_topic_moderator_without_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.moderator, '', pass_group_id=False)
def test_cohorted_topic_moderator_without_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.moderator,
'',
pass_group_id=False
)
self._assert_comments_service_called_without_group_id(mock_request)
def test_cohorted_topic_moderator_none_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.moderator, "")
def test_cohorted_topic_moderator_none_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(mock_is_forum_v2_enabled, mock_request, "cohorted_topic", self.moderator, "")
self._assert_comments_service_called_without_group_id(mock_request)
def test_cohorted_topic_moderator_with_own_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.moderator, self.moderator_cohort.id)
def test_cohorted_topic_moderator_with_own_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.moderator,
self.moderator_cohort.id
)
self._assert_comments_service_called_with_group_id(mock_request, self.moderator_cohort.id)
def test_cohorted_topic_moderator_with_other_group_id(self, mock_request):
self.call_view(mock_request, "cohorted_topic", self.moderator, self.student_cohort.id)
def test_cohorted_topic_moderator_with_other_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.moderator,
self.student_cohort.id
)
self._assert_comments_service_called_with_group_id(mock_request, self.student_cohort.id)
def test_cohorted_topic_moderator_with_invalid_group_id(self, mock_request):
def test_cohorted_topic_moderator_with_invalid_group_id(self, mock_is_forum_v2_enabled, mock_request):
invalid_id = self.student_cohort.id + self.moderator_cohort.id
response = self.call_view(mock_request, "cohorted_topic", self.moderator, invalid_id) # lint-amnesty, pylint: disable=assignment-from-no-return
response = self.call_view(mock_is_forum_v2_enabled, mock_request, "cohorted_topic", self.moderator, invalid_id) # lint-amnesty, pylint: disable=assignment-from-no-return
assert response.status_code == 500
def test_cohorted_topic_enrollment_track_invalid_group_id(self, mock_request):
def test_cohorted_topic_enrollment_track_invalid_group_id(self, mock_is_forum_v2_enabled, mock_request):
CourseModeFactory.create(course_id=self.course.id, mode_slug=CourseMode.AUDIT)
CourseModeFactory.create(course_id=self.course.id, mode_slug=CourseMode.VERIFIED)
discussion_settings = CourseDiscussionSettings.get(self.course.id)
@@ -115,7 +140,7 @@ class CohortedTopicGroupIdTestMixin(GroupIdAssertionMixin):
})
invalid_id = -1000
response = self.call_view(mock_request, "cohorted_topic", self.moderator, invalid_id) # lint-amnesty, pylint: disable=assignment-from-no-return
response = self.call_view(mock_is_forum_v2_enabled, mock_request, "cohorted_topic", self.moderator, invalid_id) # lint-amnesty, pylint: disable=assignment-from-no-return
assert response.status_code == 500
@@ -124,57 +149,95 @@ class NonCohortedTopicGroupIdTestMixin(GroupIdAssertionMixin):
Provides test cases to verify that views pass the correct `group_id` to
the comments service when requesting content in non-cohorted discussions.
"""
def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True):
def call_view(self, mock_is_forum_v2_enabled, mock_request, commentable_id, user, group_id, pass_group_id=True):
"""
Call the view for the implementing test class, constructing a request
from the parameters.
"""
pass # lint-amnesty, pylint: disable=unnecessary-pass
def test_non_cohorted_topic_student_without_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.student, '', pass_group_id=False)
def test_non_cohorted_topic_student_without_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"non_cohorted_topic",
self.student,
'',
pass_group_id=False
)
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_student_none_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.student, '')
def test_non_cohorted_topic_student_none_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(mock_is_forum_v2_enabled, mock_request, "non_cohorted_topic", self.student, '')
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_student_with_own_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.student, self.student_cohort.id)
def test_non_cohorted_topic_student_with_own_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"non_cohorted_topic",
self.student,
self.student_cohort.id
)
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_student_with_other_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.student, self.moderator_cohort.id)
def test_non_cohorted_topic_student_with_other_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"non_cohorted_topic",
self.student,
self.moderator_cohort.id
)
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_moderator_without_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.moderator, '', pass_group_id=False)
def test_non_cohorted_topic_moderator_without_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"non_cohorted_topic",
self.moderator,
"",
pass_group_id=False,
)
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_moderator_none_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.moderator, '')
def test_non_cohorted_topic_moderator_none_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(mock_is_forum_v2_enabled, mock_request, "non_cohorted_topic", self.moderator, '')
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_moderator_with_own_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.moderator, self.moderator_cohort.id)
def test_non_cohorted_topic_moderator_with_own_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"non_cohorted_topic",
self.moderator,
self.moderator_cohort.id,
)
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_moderator_with_other_group_id(self, mock_request):
self.call_view(mock_request, "non_cohorted_topic", self.moderator, self.student_cohort.id)
def test_non_cohorted_topic_moderator_with_other_group_id(self, mock_is_forum_v2_enabled, mock_request):
self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"non_cohorted_topic",
self.moderator,
self.student_cohort.id,
)
self._assert_comments_service_called_without_group_id(mock_request)
def test_non_cohorted_topic_moderator_with_invalid_group_id(self, mock_request):
def test_non_cohorted_topic_moderator_with_invalid_group_id(self, mock_is_forum_v2_enabled, mock_request):
invalid_id = self.student_cohort.id + self.moderator_cohort.id
self.call_view(mock_request, "non_cohorted_topic", self.moderator, invalid_id)
self.call_view(mock_is_forum_v2_enabled, mock_request, "non_cohorted_topic", self.moderator, invalid_id)
self._assert_comments_service_called_without_group_id(mock_request)
def test_team_discussion_id_not_cohorted(self, mock_request):
def test_team_discussion_id_not_cohorted(self, mock_is_forum_v2_enabled, mock_request):
team = CourseTeamFactory(
course_id=self.course.id,
topic_id='topic-id'
)
team.add_user(self.student)
self.call_view(mock_request, team.discussion_topic_id, self.student, '')
self.call_view(mock_is_forum_v2_enabled, mock_request, team.discussion_topic_id, self.student, '')
self._assert_comments_service_called_without_group_id(mock_request)

View File

@@ -199,7 +199,7 @@ def _get_course(course_key: CourseKey, user: User, check_tab: bool = True) -> Co
return course
def _get_thread_and_context(request, thread_id, retrieve_kwargs=None):
def _get_thread_and_context(request, thread_id, retrieve_kwargs=None, course_id=None):
"""
Retrieve the given thread and build a serializer context for it, returning
both. This function also enforces access control for the thread (checking
@@ -213,7 +213,7 @@ def _get_thread_and_context(request, thread_id, retrieve_kwargs=None):
retrieve_kwargs["with_responses"] = False
if "mark_as_read" not in retrieve_kwargs:
retrieve_kwargs["mark_as_read"] = False
cc_thread = Thread(id=thread_id).retrieve(**retrieve_kwargs)
cc_thread = Thread(id=thread_id).retrieve(course_id=course_id, **retrieve_kwargs)
course_key = CourseKey.from_string(cc_thread["course_id"])
course = _get_course(course_key, request.user)
context = get_context(course, request, cc_thread)
@@ -1645,7 +1645,8 @@ def get_thread(request, thread_id, requested_fields=None, course_id=None):
retrieve_kwargs={
"with_responses": True,
"user_id": str(request.user.id),
}
},
course_id=course_id,
)
if course_id and course_id != cc_thread.course_id:
raise ThreadNotFoundError("Thread not found.")

View File

@@ -202,7 +202,7 @@ class DiscussionNotificationSender:
while has_more_subscribers:
subscribers = Subscription.fetch(self.thread.id, query_params={'page': page})
subscribers = Subscription.fetch(self.thread.id, self.course.id, query_params={'page': page})
if page <= subscribers.num_pages:
for subscriber in subscribers.collection:
# Check if the subscriber is not the thread creator or response creator

View File

@@ -68,7 +68,7 @@ def get_context(course, request, thread=None):
moderator_user_ids = get_moderator_users_list(course.id)
ta_user_ids = get_course_ta_users_list(course.id)
requester = request.user
cc_requester = CommentClientUser.from_django_user(requester).retrieve()
cc_requester = CommentClientUser.from_django_user(requester).retrieve(course_id=course.id)
cc_requester["course_id"] = course.id
course_discussion_settings = CourseDiscussionSettings.get(course.id)
is_global_staff = GlobalStaff().has_user(requester)

View File

@@ -1248,6 +1248,22 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.maxDiff = None # pylint: disable=invalid-name
self.user = UserFactory.create()
self.register_get_user_response(self.user)
@@ -1872,6 +1888,12 @@ class CreateThreadTest(
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path")
@@ -2198,6 +2220,22 @@ class CreateCommentTest(
self.course = CourseFactory.create()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path")
@@ -2589,6 +2627,17 @@ class UpdateThreadTest(
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
@@ -3153,6 +3202,22 @@ class UpdateCommentTest(
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path")
@@ -3670,6 +3735,22 @@ class DeleteThreadTest(
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path")
@@ -3823,6 +3904,22 @@ class DeleteCommentTest(
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path")
@@ -3991,6 +4088,17 @@ class RetrieveThreadTest(
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path")

View File

@@ -54,6 +54,12 @@ class SerializerTestMixin(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetM
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.maxDiff = None # pylint: disable=invalid-name
self.user = UserFactory.create()
self.register_get_user_response(self.user)
@@ -571,6 +577,12 @@ class ThreadSerializerDeserializationTest(
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/dummy")
@@ -802,6 +814,22 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create()
self.register_get_user_response(self.user)
self.request = RequestFactory().get("/dummy")

View File

@@ -58,10 +58,27 @@ class TestNewThreadCreatedNotification(DiscussionAPIViewTestMixin, ModuleStoreTe
Setup test case
"""
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
# Creating a course
self.course = CourseFactory.create()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread",
return_value=self.course.id
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment",
return_value=self.course.id
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
# Creating relative discussion and cohort settings
CourseCohortsSettings.objects.create(course_id=str(self.course.id))
CourseDiscussionSettings.objects.create(course_id=str(self.course.id), _divided_discussions='[]')
@@ -250,8 +267,26 @@ class TestSendResponseNotifications(DiscussionAPIViewTestMixin, ModuleStoreTestC
super().setUp()
httpretty.reset()
httpretty.enable()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.course = CourseFactory.create()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread",
return_value=self.course.id
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment",
return_value=self.course.id
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
self.user_1 = UserFactory.create()
CourseEnrollment.enroll(self.user_1, self.course.id)
self.user_2 = UserFactory.create()
@@ -536,8 +571,26 @@ class TestSendCommentNotification(DiscussionAPIViewTestMixin, ModuleStoreTestCas
super().setUp()
httpretty.reset()
httpretty.enable()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.course = CourseFactory.create()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread",
return_value=self.course.id
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment",
return_value=self.course.id
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
self.user_1 = UserFactory.create()
CourseEnrollment.enroll(self.user_1, self.course.id)
self.user_2 = UserFactory.create()
@@ -603,8 +656,26 @@ class TestResponseEndorsedNotifications(DiscussionAPIViewTestMixin, ModuleStoreT
super().setUp()
httpretty.reset()
httpretty.enable()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.course = CourseFactory.create()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread",
return_value=self.course.id
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment",
return_value=self.course.id
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
self.user_1 = UserFactory.create()
CourseEnrollment.enroll(self.user_1, self.course.id)
self.user_2 = UserFactory.create()

View File

@@ -171,6 +171,12 @@ class UploadFileViewTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMi
self.user = UserFactory.create(password=self.TEST_PASSWORD)
self.course = CourseFactory.create(org='a', course='b', run='c', start=datetime.now(UTC))
self.url = reverse("upload_file", kwargs={"course_id": str(self.course.id)})
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def user_login(self):
"""
@@ -301,6 +307,7 @@ class UploadFileViewTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMi
@ddt.ddt
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_FORUM_V2": False})
class CommentViewSetListByUserTest(
ForumsEnableMixin,
CommentsServiceMockMixin,
@@ -319,6 +326,12 @@ class CommentViewSetListByUserTest(
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.user = UserFactory.create(password=self.TEST_PASSWORD)
self.register_get_user_response(self.user)
@@ -500,6 +513,12 @@ class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
def setUp(self):
super().setUp()
self.url = reverse("discussion_course", kwargs={"course_id": str(self.course.id)})
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def test_404(self):
response = self.client.get(
@@ -561,6 +580,12 @@ class RetireViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
self.superuser_client = APIClient()
self.retired_username = get_retired_username_by_username(self.user.username)
self.url = reverse("retire_discussion_user")
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def assert_response_correct(self, response, expected_status, expected_content):
"""
@@ -631,6 +656,12 @@ class ReplaceUsernamesViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
self.worker_client = APIClient()
self.new_username = "test_username_replacement"
self.url = reverse("replace_discussion_username")
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def assert_response_correct(self, response, expected_status, expected_content):
"""
@@ -733,6 +764,12 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, CommentsServiceMockMixin,
"courseware-3": {"discussion": 7, "question": 2},
}
self.register_get_course_commentable_counts_response(self.course.id, self.thread_counts_map)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def create_course(self, blocks_count, module_store, topics):
"""
@@ -988,6 +1025,12 @@ class CourseTopicsViewV3Test(DiscussionAPIViewTestMixin, CommentsServiceMockMixi
patcher.start()
self.addCleanup(patcher.stop)
self.url = reverse("course_topics_v3", kwargs={"course_id": str(self.course.id)})
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def test_basic(self):
response = self.client.get(self.url)
@@ -1024,6 +1067,12 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro
super().setUp()
self.author = UserFactory.create()
self.url = reverse("thread-list")
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def create_source_thread(self, overrides=None):
"""
@@ -1365,6 +1414,12 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
def setUp(self):
super().setUp()
self.url = reverse("thread-list")
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def test_basic(self):
self.register_get_user_response(self.user)
@@ -1437,6 +1492,17 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest
self.unsupported_media_type = JSONParser.media_type
super().setUp()
self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"})
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def test_basic(self):
self.register_get_user_response(self.user)
@@ -1581,6 +1647,17 @@ class ThreadViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
super().setUp()
self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"})
self.thread_id = "test_thread"
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def test_basic(self):
self.register_get_user_response(self.user)
@@ -1681,6 +1758,12 @@ class LearnerThreadViewAPITest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
]
self.url = reverse("discussion_learner_threads", kwargs={'course_id': str(self.course.id)})
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def update_thread(self, thread):
"""
@@ -1923,6 +2006,17 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pr
self.url = reverse("comment-list")
self.thread_id = "test_thread"
self.storage = get_profile_image_storage()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def create_source_comment(self, overrides=None):
"""
@@ -2377,6 +2471,22 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
super().setUp()
self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"})
self.comment_id = "test_comment"
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def test_basic(self):
self.register_get_user_response(self.user)
@@ -2416,6 +2526,23 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
def setUp(self):
super().setUp()
self.url = reverse("comment-list")
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def test_basic(self):
self.register_get_user_response(self.user)
@@ -2518,6 +2645,22 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes
httpretty.enable()
self.addCleanup(httpretty.reset)
self.addCleanup(httpretty.disable)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.register_get_user_response(self.user)
self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"})
@@ -2640,6 +2783,22 @@ class ThreadViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase,
super().setUp()
self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"})
self.thread_id = "test_thread"
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def test_basic(self):
self.register_get_user_response(self.user)
@@ -2693,6 +2852,22 @@ class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase
self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"})
self.thread_id = "test_thread"
self.comment_id = "test_comment"
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def make_comment_data(self, comment_id, parent_id=None, children=[]): # pylint: disable=W0102
"""
@@ -2838,6 +3013,12 @@ class CourseDiscussionSettingsAPIViewTest(APITestCase, UrlResetMixin, ModuleStor
self.path = reverse('discussion_course_settings', kwargs={'course_id': str(self.course.id)})
self.password = self.TEST_PASSWORD
self.user = UserFactory(username='staff', password=self.password, is_staff=True)
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
def _get_oauth_headers(self, user):
"""Return the OAuth headers for testing OAuth authentication"""
@@ -3127,6 +3308,12 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.course = CourseFactory.create(
org="x",
course="y",
@@ -3318,6 +3505,12 @@ class CourseActivityStatsTest(ForumsEnableMixin, UrlResetMixin, CommentsServiceM
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self) -> None:
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
self.course = CourseFactory.create()
self.course_key = str(self.course.id)
seed_permissions_roles(self.course.id)

View File

@@ -232,6 +232,22 @@ class TaskTestCase(ModuleStoreTestCase): # lint-amnesty, pylint: disable=missin
thread_permalink = '/courses/discussion/dummy_discussion_id'
self.permalink_patcher = mock.patch('lms.djangoapps.discussion.tasks.permalink', return_value=thread_permalink)
self.mock_permalink = self.permalink_patcher.start()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def tearDown(self):
super().tearDown()

View File

@@ -4,6 +4,7 @@ Tests the forum notification views.
import json
import logging
from datetime import datetime
from unittest import mock
from unittest.mock import ANY, Mock, call, patch
import ddt
@@ -109,9 +110,20 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase): # lint-amnest
config = ForumsConfig.current()
config.enabled = True
config.save()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
@patch('common.djangoapps.student.models.user.cc.User.from_django_user')
@patch('common.djangoapps.student.models.user.cc.User.active_threads')
@patch('openedx.core.djangoapps.django_comment_common.comment_client.user.User.active_threads')
def test_user_profile_exception(self, mock_threads, mock_from_django_user):
# Mock the code that makes the HTTP requests to the cs_comment_service app
@@ -323,6 +335,17 @@ class SingleThreadTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amne
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}})
self.student = UserFactory.create()
@@ -513,6 +536,20 @@ class SingleThreadQueryCountTestCase(ForumsEnableMixin, ModuleStoreTestCase):
Ensures the number of modulestore queries and number of sql queries are
independent of the number of responses retrieved for a given discussion thread.
"""
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
@ddt.data(
# split mongo: 3 queries, regardless of thread response size.
(False, 1, 2, 2, 21, 8),
@@ -582,6 +619,20 @@ class SingleThreadQueryCountTestCase(ForumsEnableMixin, ModuleStoreTestCase):
@patch('requests.request', autospec=True)
class SingleCohortedThreadTestCase(CohortedTestCase): # lint-amnesty, pylint: disable=missing-class-docstring
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def _create_mock_cohorted_thread(self, mock_request): # lint-amnesty, pylint: disable=missing-function-docstring
mock_text = "dummy content"
mock_thread_id = "test_thread_id"
@@ -644,6 +695,20 @@ class SingleCohortedThreadTestCase(CohortedTestCase): # lint-amnesty, pylint: d
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
class SingleThreadAccessTestCase(CohortedTestCase): # lint-amnesty, pylint: disable=missing-class-docstring
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def call_view(self, mock_request, commentable_id, user, group_id, thread_group_id=None, pass_group_id=True): # lint-amnesty, pylint: disable=missing-function-docstring
thread_id = "test_thread_id"
mock_request.side_effect = make_mock_request_impl(
@@ -746,6 +811,20 @@ class SingleThreadAccessTestCase(CohortedTestCase): # lint-amnesty, pylint: dis
class SingleThreadGroupIdTestCase(CohortedTestCase, GroupIdAssertionMixin): # lint-amnesty, pylint: disable=missing-class-docstring
cs_endpoint = "/threads/dummy_thread_id"
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True, is_ajax=False): # lint-amnesty, pylint: disable=missing-function-docstring
mock_request.side_effect = make_mock_request_impl(
course=self.course, text="dummy context", group_id=self.student_cohort.id
@@ -881,6 +960,22 @@ class SingleThreadContentGroupTestCase(ForumsEnableMixin, UrlResetMixin, Content
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def assert_can_access(self, user, discussion_id, thread_id, should_have_access):
"""
@@ -1046,6 +1141,7 @@ class InlineDiscussionContextTestCase(ForumsEnableMixin, ModuleStoreTestCase):
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
class InlineDiscussionGroupIdTestCase( # lint-amnesty, pylint: disable=missing-class-docstring
CohortedTestCase,
CohortedTopicGroupIdTestMixin,
@@ -1056,8 +1152,22 @@ class InlineDiscussionGroupIdTestCase( # lint-amnesty, pylint: disable=missing-
def setUp(self):
super().setUp()
self.cohorted_commentable_id = 'cohorted_topic'
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True):
def call_view(
self,
mock_is_forum_v2_enabled,
mock_request,
commentable_id,
user,
group_id,
pass_group_id=True
): # pylint: disable=arguments-differ
mock_is_forum_v2_enabled.return_value = False
kwargs = {'commentable_id': self.cohorted_commentable_id}
if group_id:
# avoid causing a server error when the LMS chokes attempting
@@ -1084,8 +1194,9 @@ class InlineDiscussionGroupIdTestCase( # lint-amnesty, pylint: disable=missing-
commentable_id
)
def test_group_info_in_ajax_response(self, mock_request):
def test_group_info_in_ajax_response(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
mock_is_forum_v2_enabled,
mock_request,
self.cohorted_commentable_id,
self.student,
@@ -1097,10 +1208,29 @@ class InlineDiscussionGroupIdTestCase( # lint-amnesty, pylint: disable=missing-
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
class ForumFormDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupIdTestMixin): # lint-amnesty, pylint: disable=missing-class-docstring
cs_endpoint = "/threads"
def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True, is_ajax=False): # pylint: disable=arguments-differ
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def call_view(
self,
mock_is_forum_v2_enabled,
mock_request,
commentable_id,
user,
group_id,
pass_group_id=True,
is_ajax=False
): # pylint: disable=arguments-differ
mock_is_forum_v2_enabled.return_value = False
kwargs = {}
if group_id:
kwargs['group_id'] = group_id
@@ -1120,8 +1250,9 @@ class ForumFormDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupIdT
**headers
)
def test_group_info_in_html_response(self, mock_request):
def test_group_info_in_html_response(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.student,
@@ -1129,8 +1260,9 @@ class ForumFormDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupIdT
)
self._assert_html_response_contains_group_info(response)
def test_group_info_in_ajax_response(self, mock_request):
def test_group_info_in_ajax_response(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.student,
@@ -1143,16 +1275,38 @@ class ForumFormDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupIdT
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupIdTestMixin): # lint-amnesty, pylint: disable=missing-class-docstring
cs_endpoint = "/active_threads"
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def call_view_for_profiled_user(
self, mock_request, requesting_user, profiled_user, group_id, pass_group_id, is_ajax=False
self,
mock_is_forum_v2_enabled,
mock_request,
requesting_user,
profiled_user,
group_id,
pass_group_id,
is_ajax=False
):
"""
Calls "user_profile" view method on behalf of "requesting_user" to get information about
the user "profiled_user".
"""
mock_is_forum_v2_enabled.return_value = False
kwargs = {}
if group_id:
kwargs['group_id'] = group_id
@@ -1172,13 +1326,23 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
**headers
)
def call_view(self, mock_request, _commentable_id, user, group_id, pass_group_id=True, is_ajax=False): # pylint: disable=arguments-differ
def call_view(
self,
mock_is_forum_v2_enabled,
mock_request,
_commentable_id,
user,
group_id,
pass_group_id=True,
is_ajax=False
): # pylint: disable=arguments-differ
return self.call_view_for_profiled_user(
mock_request, user, user, group_id, pass_group_id=pass_group_id, is_ajax=is_ajax
mock_is_forum_v2_enabled, mock_request, user, user, group_id, pass_group_id=pass_group_id, is_ajax=is_ajax
)
def test_group_info_in_html_response(self, mock_request):
def test_group_info_in_html_response(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.student,
@@ -1187,8 +1351,9 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
)
self._assert_html_response_contains_group_info(response)
def test_group_info_in_ajax_response(self, mock_request):
def test_group_info_in_ajax_response(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.student,
@@ -1200,7 +1365,14 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
)
def _test_group_id_passed_to_user_profile(
self, mock_request, expect_group_id_in_request, requesting_user, profiled_user, group_id, pass_group_id
self,
mock_is_forum_v2_enabled,
mock_request,
expect_group_id_in_request,
requesting_user,
profiled_user,
group_id,
pass_group_id
):
"""
Helper method for testing whether or not group_id was passed to the user_profile request.
@@ -1221,10 +1393,11 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
has_course_id = "course_id" in params
if (for_specific_course and has_course_id) or (not for_specific_course and not has_course_id):
return params
pytest.fail("Did not find appropriate user_profile call for 'for_specific_course'=" + for_specific_course)
pytest.fail(f"Did not find appropriate user_profile call for 'for_specific_course'={for_specific_course}")
mock_request.reset_mock()
self.call_view_for_profiled_user(
mock_is_forum_v2_enabled,
mock_request,
requesting_user,
profiled_user,
@@ -1243,7 +1416,7 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
else:
assert 'group_id' not in params_with_course_id
def test_group_id_passed_to_user_profile_student(self, mock_request):
def test_group_id_passed_to_user_profile_student(self, mock_is_forum_v2_enabled, mock_request):
"""
Test that the group id is always included when requesting user profile information for a particular
course if the requester does not have discussion moderation privileges.
@@ -1254,7 +1427,13 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
(non-privileged user).
"""
self._test_group_id_passed_to_user_profile(
mock_request, True, self.student, profiled_user, self.student_cohort.id, pass_group_id
mock_is_forum_v2_enabled,
mock_request,
True,
self.student,
profiled_user,
self.student_cohort.id,
pass_group_id
)
# In all these test cases, the requesting_user is the student (non-privileged user).
@@ -1264,7 +1443,7 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
verify_group_id_always_present(profiled_user=self.moderator, pass_group_id=True)
verify_group_id_always_present(profiled_user=self.moderator, pass_group_id=False)
def test_group_id_user_profile_moderator(self, mock_request):
def test_group_id_user_profile_moderator(self, mock_is_forum_v2_enabled, mock_request):
"""
Test that the group id is only included when a privileged user requests user profile information for a
particular course and user if the group_id is explicitly passed in.
@@ -1274,7 +1453,13 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
Helper method to verify that group_id is present.
"""
self._test_group_id_passed_to_user_profile(
mock_request, True, self.moderator, profiled_user, requested_cohort.id, pass_group_id
mock_is_forum_v2_enabled,
mock_request,
True,
self.moderator,
profiled_user,
requested_cohort.id,
pass_group_id
)
def verify_group_id_not_present(profiled_user, pass_group_id, requested_cohort=self.moderator_cohort):
@@ -1282,7 +1467,13 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
Helper method to verify that group_id is not present.
"""
self._test_group_id_passed_to_user_profile(
mock_request, False, self.moderator, profiled_user, requested_cohort.id, pass_group_id
mock_is_forum_v2_enabled,
mock_request,
False,
self.moderator,
profiled_user,
requested_cohort.id,
pass_group_id
)
# In all these test cases, the requesting_user is the moderator (privileged user).
@@ -1301,10 +1492,28 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
class FollowedThreadsDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupIdTestMixin): # lint-amnesty, pylint: disable=missing-class-docstring
cs_endpoint = "/subscribed_threads"
def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True):
def setUp(self):
super().setUp()
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
def call_view(
self,
mock_is_forum_v2_enabled,
mock_request,
commentable_id,
user,
group_id,
pass_group_id=True
): # pylint: disable=arguments-differ
mock_is_forum_v2_enabled.return_value = False
kwargs = {}
if group_id:
kwargs['group_id'] = group_id
@@ -1325,8 +1534,9 @@ class FollowedThreadsDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGr
user.id
)
def test_group_info_in_ajax_response(self, mock_request):
def test_group_info_in_ajax_response(self, mock_is_forum_v2_enabled, mock_request):
response = self.call_view(
mock_is_forum_v2_enabled,
mock_request,
"cohorted_topic",
self.student,
@@ -1528,6 +1738,22 @@ class CommentsServiceRequestHeadersTestCase(ForumsEnableMixin, UrlResetMixin, Mo
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.get_course_id_by_comment"
)
self.mock_get_course_id_by_comment = patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
username = "foo"
password = "bar"
@@ -1742,6 +1968,20 @@ class SingleThreadUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCase,
with super().setUpClassAndTestData():
cls.course = CourseFactory.create(discussion_topics={'dummy_discussion_id': {'id': 'dummy_discussion_id'}})
def setUp(self):
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
@classmethod
def setUpTestData(cls):
super().setUpTestData()
@@ -1858,7 +2098,17 @@ class EnterpriseConsentTestCase(EnterpriseTestConsentRequired, ForumsEnableMixin
def setUp(self):
# Invoke UrlResetMixin setUp
super().setUp()
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
username = "foo"
password = "bar"
@@ -2195,6 +2445,17 @@ class ThreadViewedEventTestCase(EventTestMixin, ForumsEnableMixin, UrlResetMixin
def setUp(self): # pylint: disable=arguments-differ
super().setUp('lms.djangoapps.discussion.django_comment_client.base.views.tracker')
patcher = mock.patch(
'openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled',
return_value=False
)
patcher.start()
self.addCleanup(patcher.stop)
patcher = mock.patch(
"openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.get_course_id_by_thread"
)
self.mock_get_course_id_by_thread = patcher.start()
self.addCleanup(patcher.stop)
self.course = CourseFactory.create(
teams_configuration=TeamsConfig({
'topics': [{

View File

@@ -1,6 +1,7 @@
"""
Discussions feature toggles
"""
from openedx.core.djangoapps.discussions.config.waffle import WAFFLE_FLAG_NAMESPACE
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
@@ -11,4 +12,6 @@ from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
# .. toggle_use_cases: temporary, open_edx
# .. toggle_creation_date: 2021-11-05
# .. toggle_target_removal_date: 2022-12-05
ENABLE_DISCUSSIONS_MFE = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.enable_discussions_mfe', __name__)
ENABLE_DISCUSSIONS_MFE = CourseWaffleFlag(
f"{WAFFLE_FLAG_NAMESPACE}.enable_discussions_mfe", __name__
)