From 284e7da3c367c5ff4c5be80561f281963d1397e0 Mon Sep 17 00:00:00 2001 From: Muhammad Faraz Maqsood Date: Fri, 27 Sep 2024 13:57:27 +0500 Subject: [PATCH] feat: use new coursewaffle flag to run old code - add `ENABLE_FORUM_V2` course waffle flag to switch between old code i.e. cs_comment_service and new code i.e. forum v2. - mock course waffle flag is_enabled method i.e. ENABLE_FORUM_V2.is_enabled(), so that old unit tests can be run and passed. - refactor code(that parts of code whose native APIs are implemented till now) where we call the native APIs --- .../django_comment_client/base/tests.py | 348 ++++++++++-------- .../django_comment_client/tests/group_id.py | 84 ++--- .../discussion/rest_api/tests/test_api.py | 211 +++-------- .../rest_api/tests/test_serializers.py | 21 +- .../discussion/rest_api/tests/test_views.py | 141 +++---- .../discussion/rest_api/tests/utils.py | 20 +- lms/djangoapps/discussion/toggles.py | 25 +- .../comment_client/course.py | 15 +- .../comment_client/models.py | 181 +++++---- .../comment_client/thread.py | 39 +- .../comment_client/user.py | 32 +- 11 files changed, 567 insertions(+), 550 deletions(-) diff --git a/lms/djangoapps/discussion/django_comment_client/base/tests.py b/lms/djangoapps/discussion/django_comment_client/base/tests.py index ecee12dea055..a1eb742e2e96 100644 --- a/lms/djangoapps/discussion/django_comment_client/base/tests.py +++ b/lms/djangoapps/discussion/django_comment_client/base/tests.py @@ -78,13 +78,11 @@ def _create_response_mock(self, data): ) def _set_mock_request_data(self, mock_request, data): - if mock_request.mock._mock_name != "request": - mock_request.return_value = data - else: - mock_request.return_value = self._create_response_mock(data) + mock_request.return_value = self._create_response_mock(data) @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True) +@patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) class CreateThreadGroupIdTestCase( MockRequestSetupMixin, CohortedTestCase, @@ -93,7 +91,8 @@ class CreateThreadGroupIdTestCase( ): cs_endpoint = "/threads" - 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): + 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: @@ -108,8 +107,9 @@ def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id= 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, @@ -119,6 +119,7 @@ def test_group_info_in_response(self, mock_request): @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True) +@patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) @disable_signal(views, 'thread_edited') @disable_signal(views, 'thread_voted') @disable_signal(views, 'thread_deleted') @@ -130,11 +131,13 @@ class ThreadActionGroupIdTestCase( 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 self._set_mock_request_data( mock_request, { @@ -157,57 +160,58 @@ def call_view( **(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) - @patch('openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.pin_thread', autospec=True) - def test_pin(self, mock_request, mock_pin_thread): + def test_pin(self, mock_is_forum_v2_enabled, mock_request): response = self.call_view( "pin_thread", - mock_pin_thread, + mock_is_forum_v2_enabled, + mock_request, user=self.moderator ) self._assert_json_response_contains_group_info(response) - - @patch('openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.unpin_thread', autospec=True) - def test_unpin(self, mock_request, mock_unpin_thread): response = self.call_view( "un_pin_thread", - mock_unpin_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 ) @@ -287,10 +291,11 @@ def _setup_mock_request(self, mock_request, include_depth=False): 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", @@ -357,10 +362,11 @@ def create_thread_helper(self, mock_request, extra_request_data=None, extra_resp ) 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 @@ -383,6 +389,7 @@ def update_thread_helper(self, mock_request): @ddt.ddt @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True) +@patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) @disable_signal(views, 'thread_created') @disable_signal(views, 'thread_edited') class ViewsQueryCountTestCase( @@ -421,22 +428,23 @@ def inner(self, default_store, block_count, mongo_calls, sql_queries, *args, **k ) @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('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) class ViewsTestCase( ForumsEnableMixin, UrlResetMixin, @@ -504,11 +512,11 @@ def assert_discussion_signals(self, signal, user=None): 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, @@ -520,15 +528,15 @@ def test_create_thread_standalone(self, mock_request): 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( @@ -539,7 +547,8 @@ def test_follow_unfollow_thread_signals(self, view_name, signal, mock_request): ) 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, @@ -558,11 +567,8 @@ def test_delete_thread(self, mock_request): assert response.status_code == 200 assert mock_request.called - ### not working - # @patch('openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.delete_comment', autospec=True) - # def test_delete_comment(self, mock_request, mock_delete_comment): - # self._set_mock_request_data(mock_delete_comment, { - 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, @@ -579,19 +585,18 @@ def test_delete_comment(self, mock_request): comment_id=test_comment_id ) assert response.status_code == 200 - # assert mock_delete_comment.called - # args = mock_delete_comment.call_args[0] assert mock_request.called args = mock_request.call_args[0] 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) @@ -599,87 +604,97 @@ def _test_request_error(self, view_name, view_kwargs, data, mock_request): 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( @@ -691,55 +706,62 @@ def test_create_comment(self, mock_request): ) 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" @@ -761,13 +783,14 @@ def test_update_comment_basic(self, mock_request): 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", @@ -839,13 +862,14 @@ def flag_thread(self, mock_request, is_closed): 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", @@ -918,13 +942,14 @@ def un_flag_thread(self, mock_request, is_closed): 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", @@ -989,13 +1014,14 @@ def flag_comment(self, mock_request, is_closed): 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", @@ -1067,7 +1093,8 @@ def un_flag_comment(self, mock_request, is_closed): ('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( @@ -1078,7 +1105,8 @@ def test_voting(self, view_name, item_id, signal, mock_request): ) 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): @@ -1092,6 +1120,7 @@ def test_endorse_comment(self, mock_request): @patch("openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request", autospec=True) +@patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) @disable_signal(views, 'comment_endorsed') class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase, MockRequestSetupMixin): @@ -1120,43 +1149,43 @@ def setUpTestData(cls): def setUp(self): super().setUp() - @patch('openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.pin_thread', autospec=True) - def test_pin_thread_as_student(self, mock_request, mock_pin_thread): - self._set_mock_request_data(mock_pin_thread, {}) + 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( reverse("pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) assert response.status_code == 401 - @patch('openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.pin_thread', autospec=True) - def test_pin_thread_as_moderator(self, mock_request, mock_pin_thread): - self._set_mock_request_data(mock_pin_thread, {}) + 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( reverse("pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) assert response.status_code == 200 - @patch('openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.unpin_thread', autospec=True) - def test_un_pin_thread_as_student(self, mock_request, mock_unpin_thread): - self._set_mock_request_data(mock_unpin_thread, {}) + 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( reverse("un_pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) assert response.status_code == 401 - @patch('openedx.core.djangoapps.django_comment_common.comment_client.thread.forum_api.unpin_thread', autospec=True) - def test_un_pin_thread_as_moderator(self, mock_request, mock_unpin_thread): - self._set_mock_request_data(mock_unpin_thread, {}) + 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( reverse("un_pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) 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: @@ -1165,10 +1194,12 @@ def handle_request(*args, **kwargs): 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"} @@ -1179,12 +1210,9 @@ def test_endorse_response_as_staff(self, mock_request): ) assert response.status_code == 200 - # @patch('openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.update_comment', autospec=True) - # def test_endorse_response_as_student(self, mock_update_comment, mock_request): - # self._set_mock_request_thread_and_comment( - # mock_update_comment, - 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"}, @@ -1196,12 +1224,9 @@ def test_endorse_response_as_student(self, mock_request): ) assert response.status_code == 401 - # @patch('openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.update_comment', autospec=True) - # def test_endorse_response_as_student_question_author(self, mock_request, mock_update_comment): - # self._set_mock_request_thread_and_comment( - # mock_update_comment, - 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"} @@ -1234,10 +1259,12 @@ def setUpTestData(cls): 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('lms.djangoapps.discussion.toggles.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 @@ -1280,7 +1307,9 @@ def setUpTestData(cls): 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('lms.djangoapps.discussion.toggles.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, @@ -1321,7 +1350,9 @@ def setUpTestData(cls): 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('lms.djangoapps.discussion.toggles.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, @@ -1368,7 +1399,9 @@ def setUpTestData(cls): 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('lms.djangoapps.discussion.toggles.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, @@ -1384,6 +1417,7 @@ def _test_unicode_data(self, text, mock_request): @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True) +@patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) class CommentActionTestCase( MockRequestSetupMixin, CohortedTestCase, @@ -1392,11 +1426,13 @@ 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 self._set_mock_request_data( mock_request, { @@ -1419,9 +1455,9 @@ def call_view( **(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) @@ -1450,10 +1486,12 @@ def setUpTestData(cls): 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('lms.djangoapps.discussion.toggles.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, @@ -1478,6 +1516,7 @@ def _test_unicode_data(self, text, mock_request): @ddt.ddt @patch("openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request", autospec=True) +@patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) @disable_signal(views, 'thread_voted') @disable_signal(views, 'thread_edited') @disable_signal(views, 'comment_created') @@ -1587,12 +1626,13 @@ def create_users_and_enroll(coursemode): 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) self.client.login(username=user.username, password=self.password) @@ -1618,7 +1658,7 @@ def _setup_mock(self, user, mock_request, data): ('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). """ @@ -1628,7 +1668,7 @@ def test_update_thread(self, user, thread_author, commentable_id, status_code, d 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, @@ -1668,20 +1708,12 @@ def test_update_thread(self, user, thread_author, commentable_id, status_code, d ('group_moderator', 'cohorted', 'team_commentable_id', 401, CourseDiscussionSettings.NONE) ) @ddt.unpack - ### not working - # @patch('openedx.core.djangoapps.django_comment_common.comment_client.models.forum_api.delete_comment', autospec=True) - # def test_delete_comment(self, user, comment_author, commentable_id, status_code, division_scheme, mock_request, mock_delete_comment): - # commentable_id = getattr(self, commentable_id) - # comment_author = getattr(self, comment_author) - # self.change_divided_discussion_settings(division_scheme) - - # self._setup_mock(user, mock_delete_comment, { - 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), @@ -1704,12 +1736,12 @@ def test_delete_comment(self, user, comment_author, commentable_id, status_code, @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( @@ -1725,13 +1757,13 @@ def test_create_comment(self, user, commentable_id, status_code, mock_request): @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( @@ -1748,14 +1780,14 @@ def test_create_sub_comment(self, user, commentable_id, status_code, mock_reques @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, @@ -1775,14 +1807,14 @@ def test_comment_actions(self, user, commentable_id, status_code, mock_request): @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", @@ -1824,12 +1856,14 @@ def setUpTestData(cls): @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('lms.djangoapps.discussion.toggles.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', @@ -1866,12 +1900,14 @@ def test_response_event(self, mock_request, mock_emit): @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('lms.djangoapps.discussion.toggles.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, @@ -1908,6 +1944,7 @@ def test_comment_event(self, mock_request, mock_emit): @patch('eventtracking.tracker.emit') @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True) + @patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', autospec=True) @ddt.data(( 'create_thread', 'edx.forum.thread.created', { @@ -1929,7 +1966,7 @@ def test_comment_event(self, mock_request, mock_emit): {'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) @@ -1938,6 +1975,7 @@ def test_team_events(self, view_name, event_name, view_data, view_kwargs, mock_r 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, @@ -1976,9 +2014,11 @@ def test_team_events(self, view_name, event_name, view_data, view_kwargs, mock_r @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('lms.djangoapps.discussion.toggles.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', @@ -2004,11 +2044,13 @@ def test_thread_voted_event(self, view_name, obj_id_name, obj_type, mock_request @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('lms.djangoapps.discussion.toggles.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', @@ -2058,10 +2100,11 @@ def setUpTestData(cls): 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, @@ -2074,16 +2117,18 @@ def make_request(self, method='get', course_id=None, **kwargs): request.view_name = "users" return views.users(request, course_id=str(course_id)) - @patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user', autospec=True) - def test_finds_exact_match(self, mock_request): - self.set_post_counts(mock_request) + @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True) + @patch('lms.djangoapps.discussion.toggles.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('lms.djangoapps.discussion.toggles.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'] == [] @@ -2118,9 +2163,10 @@ def test_requires_requestor_enrolled_in_course(self): assert 'errors' in content assert 'users' not in content - @patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user', 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.django_comment_common.comment_client.utils.requests.request', autospec=True) + @patch('lms.djangoapps.discussion.toggles.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'] == [] diff --git a/lms/djangoapps/discussion/django_comment_client/tests/group_id.py b/lms/djangoapps/discussion/django_comment_client/tests/group_id.py index 78853293ec46..1e67ca2e0676 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/group_id.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/group_id.py @@ -60,51 +60,51 @@ 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 +115,7 @@ def test_cohorted_topic_enrollment_track_invalid_group_id(self, mock_request): }) 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 +124,57 @@ 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): + response = 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): + response = 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): + response = 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): + response = 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): + response = 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): + response = 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): + response = 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) + response = 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, '') + response = 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) diff --git a/lms/djangoapps/discussion/rest_api/tests/test_api.py b/lms/djangoapps/discussion/rest_api/tests/test_api.py index 6b333d241a45..da6ebfecbcdb 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_api.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_api.py @@ -4,11 +4,9 @@ import itertools -import json import random from datetime import datetime, timedelta from unittest import mock -import unittest from urllib.parse import parse_qs, urlencode, urlparse, urlunparse import ddt @@ -708,16 +706,6 @@ def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -727,7 +715,7 @@ def setUp(self): self.addCleanup(httpretty.disable) self.maxDiff = None # pylint: disable=invalid-name self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) @@ -1253,16 +1241,6 @@ def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -1272,7 +1250,7 @@ def setUp(self): self.addCleanup(httpretty.disable) self.maxDiff = None # pylint: disable=invalid-name self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) @@ -1418,7 +1396,7 @@ def test_basic_query_params(self): page_size=14 ) self.assert_query_params_equal( - httpretty.httpretty.latest_requests[-1], + httpretty.httpretty.latest_requests[-2], { "user_id": [str(self.user.id)], "mark_as_read": ["False"], @@ -1728,19 +1706,6 @@ class GetUserCommentsTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedMod """ Tests for get_user_comments. """ - @classmethod - def setUpClass(cls): - super().setUpClass() - - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): @@ -1756,7 +1721,7 @@ def setUp(self): # create staff user so that we don't need to worry about # permissions here self.user = UserFactory.create(is_staff=True) - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get(f'/api/discussion/v1/users/{self.user.username}/{self.course.id}') self.request.user = self.user @@ -1899,20 +1864,6 @@ class CreateThreadTest( 'nonummy metus.' ) - @classmethod - def setUpClass(cls): - super().setUpClass() - - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -1921,8 +1872,11 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() + self.addCleanup(patcher.stop) self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) @@ -2221,20 +2175,6 @@ def test_invalid_field(self): create_thread(self.request, data) -class MockRequestSetupMixin: - def _create_response_mock(self, data): - return mock.Mock( - text=json.dumps(data), - json=mock.Mock(return_value=data), - status_code=200 - ) - - def _set_mock_request_data(self, mock_request, data): - if mock_request.mock._mock_name != "request": - mock_request.return_value = data - else: - mock_request.return_value = self._create_response_mock(data) - @ddt.ddt @disable_signal(api, 'comment_created') @disable_signal(api, 'comment_voted') @@ -2252,16 +2192,6 @@ class CreateCommentTest( def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): @@ -2271,8 +2201,11 @@ def setUp(self): self.course = CourseFactory.create() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() + self.addCleanup(patcher.stop) self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) @@ -2654,16 +2587,6 @@ def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -2672,9 +2595,12 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() + self.addCleanup(patcher.stop) self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) @@ -2704,7 +2630,7 @@ def create_user_with_request(self): Create a user and an associated request for a specific course enrollment. """ user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, user) + self.register_get_user_response(user) request = RequestFactory().get("/test_path") request.user = user CourseEnrollmentFactory.create(user=user, course_id=self.course.id) @@ -2713,7 +2639,7 @@ def create_user_with_request(self): def test_empty(self): """Check that an empty update does not make any modifying requests.""" # Ensure that the default following value of False is not applied implicitly - self.register_get_user_response(self.mock_get_user, self.user, subscribed_thread_ids=["test_thread"]) + self.register_get_user_response(self.user, subscribed_thread_ids=["test_thread"]) self.register_thread() update_thread(self.request, "test_thread", {}) for request in httpretty.httpretty.latest_requests: @@ -2836,7 +2762,7 @@ def test_following(self, old_following, new_following, mock_emit): DELETEd according to the new_following value. """ if old_following: - self.register_get_user_response(self.mock_get_user, self.user, subscribed_thread_ids=["test_thread"]) + self.register_get_user_response(self.user, subscribed_thread_ids=["test_thread"]) self.register_subscription_response(self.user) self.register_thread() data = {"following": new_following} @@ -2885,7 +2811,7 @@ def test_voted(self, current_vote_status, new_vote_status, mock_emit): user1, request1 = self.create_user_with_request() if current_vote_status: - self.register_get_user_response(self.mock_get_user, user1, upvoted_ids=["test_thread"]) + self.register_get_user_response(user1, upvoted_ids=["test_thread"]) self.register_thread_votes_response("test_thread") self.register_thread() data = {"voted": new_vote_status} @@ -2931,7 +2857,7 @@ def test_vote_count(self, current_vote_status, first_vote, second_vote): starting_vote_count = 0 user, request = self.create_user_with_request() if current_vote_status: - self.register_get_user_response(self.mock_get_user, user, upvoted_ids=["test_thread"]) + self.register_get_user_response(user, upvoted_ids=["test_thread"]) starting_vote_count = 1 self.register_thread_votes_response("test_thread") self.register_thread(overrides={"votes": {"up_count": starting_vote_count}}) @@ -2965,10 +2891,10 @@ def test_vote_count_two_users( vote_count = 0 if current_user1_vote: - self.register_get_user_response(self.mock_get_user, user1, upvoted_ids=["test_thread"]) + self.register_get_user_response(user1, upvoted_ids=["test_thread"]) vote_count += 1 if current_user2_vote: - self.register_get_user_response(self.mock_get_user, user2, upvoted_ids=["test_thread"]) + self.register_get_user_response(user2, upvoted_ids=["test_thread"]) vote_count += 1 for (current_vote, user_vote, request) in \ @@ -2985,11 +2911,11 @@ def test_vote_count_two_users( elif user_vote: vote_count += 1 assert result['vote_count'] == vote_count - self.register_get_user_response(self.mock_get_user, self.user, upvoted_ids=["test_thread"]) + self.register_get_user_response(self.user, upvoted_ids=["test_thread"]) else: vote_count -= 1 assert result['vote_count'] == vote_count - self.register_get_user_response(self.mock_get_user, self.user, upvoted_ids=[]) + self.register_get_user_response(self.user, upvoted_ids=[]) @ddt.data(*itertools.product([True, False], [True, False])) @ddt.unpack @@ -3004,7 +2930,7 @@ def test_abuse_flagged(self, old_flagged, new_flagged, mock_emit): update should be made. Otherwise, a PUT should be made to the flag or or unflag endpoint according to the new_flagged value. """ - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.register_thread_flag_response("test_thread") self.register_thread({"abuse_flaggers": [str(self.user.id)] if old_flagged else []}) data = {"abuse_flagged": new_flagged} @@ -3060,7 +2986,7 @@ def test_thread_un_abuse_flag_for_moderator_role(self, is_author, remove_all, mo thread as unreported. """ _assign_role_to_user(user=self.user, course_id=self.course.id, role=FORUM_ROLE_ADMINISTRATOR) - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.register_thread_flag_response("test_thread") self.register_thread({"abuse_flaggers": ["11"], "user_id": str(self.user.id) if is_author else "12"}) data = {"abuse_flagged": False} @@ -3114,7 +3040,6 @@ def test_update_thread_with_edit_reason_code(self, role_name, mock_emit): Test editing comments, specifying and retrieving edit reason codes. """ _assign_role_to_user(user=self.user, course_id=self.course.id, role=role_name) - self.register_thread({"user_id": str(self.user.id + 1)}) try: result = update_thread(self.request, "test_thread", { @@ -3228,16 +3153,6 @@ def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -3247,8 +3162,11 @@ def setUp(self): self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() + self.addCleanup(patcher.stop) self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) @@ -3287,7 +3205,7 @@ def create_user_with_request(self): Create a user and an associated request for a specific course enrollment. """ user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, user) + self.register_get_user_response(user) request = RequestFactory().get("/test_path") request.user = user CourseEnrollmentFactory.create(user=user, course_id=self.course.id) @@ -3487,7 +3405,7 @@ def test_voted(self, current_vote_status, new_vote_status, mock_emit): vote_count = 0 user1, request1 = self.create_user_with_request() if current_vote_status: - self.register_get_user_response(self.mock_get_user, user1, upvoted_ids=["test_comment"]) + self.register_get_user_response(user1, upvoted_ids=["test_comment"]) vote_count = 1 self.register_comment_votes_response("test_comment") self.register_comment(overrides={"votes": {"up_count": vote_count}}) @@ -3536,7 +3454,7 @@ def test_vote_count(self, current_vote_status, first_vote, second_vote): starting_vote_count = 0 user1, request1 = self.create_user_with_request() if current_vote_status: - self.register_get_user_response(self.mock_get_user, user1, upvoted_ids=["test_comment"]) + self.register_get_user_response(user1, upvoted_ids=["test_comment"]) starting_vote_count = 1 self.register_comment_votes_response("test_comment") self.register_comment(overrides={"votes": {"up_count": starting_vote_count}}) @@ -3569,10 +3487,10 @@ def test_vote_count_two_users( vote_count = 0 if current_user1_vote: - self.register_get_user_response(self.mock_get_user, user1, upvoted_ids=["test_comment"]) + self.register_get_user_response(user1, upvoted_ids=["test_comment"]) vote_count += 1 if current_user2_vote: - self.register_get_user_response(self.mock_get_user, user2, upvoted_ids=["test_comment"]) + self.register_get_user_response(user2, upvoted_ids=["test_comment"]) vote_count += 1 for (current_vote, user_vote, request) in \ @@ -3583,19 +3501,17 @@ def test_vote_count_two_users( self.register_comment(overrides={"votes": {"up_count": vote_count}}) data = {"voted": user_vote} - # mock_path = f"djangoapps.discussion.rest_api.api.update_comment" - # with mock.patch(mock_path) as update_comment_patch: result = update_comment(request, "test_comment", data) if current_vote == user_vote: assert result['vote_count'] == vote_count elif user_vote: vote_count += 1 assert result['vote_count'] == vote_count - self.register_get_user_response(self.mock_get_user, self.user, upvoted_ids=["test_comment"]) + self.register_get_user_response(self.user, upvoted_ids=["test_comment"]) else: vote_count -= 1 assert result['vote_count'] == vote_count - self.register_get_user_response(self.mock_get_user, self.user, upvoted_ids=[]) + self.register_get_user_response(self.user, upvoted_ids=[]) @ddt.data(*itertools.product([True, False], [True, False])) @ddt.unpack @@ -3610,7 +3526,7 @@ def test_abuse_flagged(self, old_flagged, new_flagged, mock_emit): update should be made. Otherwise, a PUT should be made to the flag or or unflag endpoint according to the new_flagged value. """ - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.register_comment_flag_response("test_comment") self.register_comment({"abuse_flaggers": [str(self.user.id)] if old_flagged else []}) data = {"abuse_flagged": new_flagged} @@ -3662,7 +3578,7 @@ def test_comment_un_abuse_flag_for_moderator_role(self, is_author, remove_all, m comment as unreported. """ _assign_role_to_user(user=self.user, course_id=self.course.id, role=FORUM_ROLE_ADMINISTRATOR) - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.register_comment_flag_response("test_comment") self.register_comment({"abuse_flaggers": ["11"], "user_id": str(self.user.id) if is_author else "12"}) data = {"abuse_flagged": False} @@ -3759,16 +3675,6 @@ def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -3776,8 +3682,11 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() + self.addCleanup(patcher.stop) self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user self.thread_id = "test_thread" @@ -3921,16 +3830,7 @@ class DeleteCommentTest( def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() + @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): @@ -3939,8 +3839,11 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() + self.addCleanup(patcher.stop) self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user self.thread_id = "test_thread" @@ -4094,22 +3997,12 @@ class RetrieveThreadTest( UrlResetMixin, SharedModuleStoreTestCase ): - """Tests for get_thread""" + """Tests for get_thread""" @classmethod def setUpClass(cls): super().setUpClass() cls.course = CourseFactory.create() - # Patch get_user for the entire class - cls.patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - cls.mock_get_user = cls.patcher.start() - - @classmethod - def tearDownClass(cls): - # Stop the patcher - cls.patcher.stop() - super().tearDownClass() - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() @@ -4118,7 +4011,7 @@ def setUp(self): self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) self.user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, self.user) + self.register_get_user_response(self.user) self.request = RequestFactory().get("/test_path") self.request.user = self.user self.thread_id = "test_thread" @@ -4159,7 +4052,7 @@ def test_thread_id_not_found(self): def test_nonauthor_enrolled_in_course(self): non_author_user = UserFactory.create() - self.register_get_user_response(self.mock_get_user, non_author_user) + self.register_get_user_response(non_author_user) CourseEnrollmentFactory.create(user=non_author_user, course_id=self.course.id) self.register_thread() self.request.user = non_author_user diff --git a/lms/djangoapps/discussion/rest_api/tests/test_serializers.py b/lms/djangoapps/discussion/rest_api/tests/test_serializers.py index 539d2b29ff9b..8075f0438092 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_serializers.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_serializers.py @@ -54,12 +54,9 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.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) @@ -577,12 +574,9 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.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") @@ -814,12 +808,9 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.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") diff --git a/lms/djangoapps/discussion/rest_api/tests/test_views.py b/lms/djangoapps/discussion/rest_api/tests/test_views.py index f8514274cf17..337b24e4276f 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_views.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_views.py @@ -171,10 +171,8 @@ def setUp(self): 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)}) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def user_login(self): @@ -306,6 +304,7 @@ def test_file_upload_with_no_data(self): @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, @@ -324,9 +323,8 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) self.user = UserFactory.create(password=self.TEST_PASSWORD) @@ -509,12 +507,9 @@ class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): def setUp(self): super().setUp() self.url = reverse("discussion_course", kwargs={"course_id": str(self.course.id)}) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) - def test_404(self): response = self.client.get( reverse("course_topics", kwargs={"course_id": "non/existent/course"}) @@ -575,10 +570,8 @@ def setUp(self): self.superuser_client = APIClient() self.retired_username = get_retired_username_by_username(self.user.username) self.url = reverse("retire_discussion_user") - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def assert_response_correct(self, response, expected_status, expected_content): @@ -650,10 +643,8 @@ def setUp(self): self.worker_client = APIClient() self.new_username = "test_username_replacement" self.url = reverse("replace_discussion_username") - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def assert_response_correct(self, response, expected_status, expected_content): @@ -757,10 +748,8 @@ def setUp(self): "courseware-3": {"discussion": 7, "question": 2}, } self.register_get_course_commentable_counts_response(self.course.id, self.thread_counts_map) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def create_course(self, blocks_count, module_store, topics): @@ -1017,10 +1006,8 @@ def setUp(self) -> None: patcher.start() self.addCleanup(patcher.stop) self.url = reverse("course_topics_v3", kwargs={"course_id": str(self.course.id)}) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def test_basic(self): @@ -1058,10 +1045,8 @@ def setUp(self): super().setUp() self.author = UserFactory.create() self.url = reverse("thread-list") - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def create_source_thread(self, overrides=None): @@ -1404,10 +1389,8 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): def setUp(self): super().setUp() self.url = reverse("thread-list") - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def test_basic(self): @@ -1481,10 +1464,8 @@ def setUp(self): self.unsupported_media_type = JSONParser.media_type super().setUp() self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"}) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def test_basic(self): @@ -1599,7 +1580,6 @@ def test_patch_read_non_owner_user(self): thread_owner_user = UserFactory.create(password=self.password) CourseEnrollmentFactory.create(user=thread_owner_user, course_id=self.course.id) self.register_get_user_response(thread_owner_user) - self.register_get_user_response(self.user) self.register_thread({ "username": thread_owner_user.username, "user_id": str(thread_owner_user.id), @@ -1631,10 +1611,8 @@ def setUp(self): super().setUp() self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"}) self.thread_id = "test_thread" - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def test_basic(self): @@ -1736,10 +1714,8 @@ def setUp(self): ] self.url = reverse("discussion_learner_threads", kwargs={'course_id': str(self.course.id)}) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def update_thread(self, thread): @@ -1983,10 +1959,8 @@ def setUp(self): self.url = reverse("comment-list") self.thread_id = "test_thread" self.storage = get_profile_image_storage() - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def create_source_comment(self, overrides=None): @@ -2107,7 +2081,7 @@ def test_basic(self): ) ) self.assert_query_params_equal( - httpretty.httpretty.latest_requests[-1], + httpretty.httpretty.latest_requests[-2], { "resp_skip": ["0"], "resp_limit": ["10"], @@ -2143,7 +2117,7 @@ def test_pagination(self): {"developer_message": "Page not found (No results on this page)."} ) self.assert_query_params_equal( - httpretty.httpretty.latest_requests[-1], + httpretty.httpretty.latest_requests[-2], { "resp_skip": ["68"], "resp_limit": ["4"], @@ -2418,7 +2392,7 @@ def test_reverse_order_sort(self): }) self.client.get(self.url, {"thread_id": self.thread_id, "reverse_order": True}) self.assert_query_params_equal( - httpretty.httpretty.latest_requests[-1], + httpretty.httpretty.latest_requests[-2], { "resp_skip": ["0"], "resp_limit": ["10"], @@ -2442,10 +2416,8 @@ def setUp(self): super().setUp() self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"}) self.comment_id = "test_comment" - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def test_basic(self): @@ -2486,10 +2458,8 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): def setUp(self): super().setUp() self.url = reverse("comment-list") - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def test_basic(self): @@ -2593,12 +2563,9 @@ def setUp(self): httpretty.enable() self.addCleanup(httpretty.reset) self.addCleanup(httpretty.disable) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) - self.register_get_user_response(self.user) self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"}) @@ -2721,12 +2688,10 @@ def setUp(self): super().setUp() self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"}) self.thread_id = "test_thread" - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.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) cs_thread = make_minimal_cs_thread({ @@ -2779,10 +2744,8 @@ def setUp(self): self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"}) self.thread_id = "test_thread" self.comment_id = "test_comment" - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def make_comment_data(self, comment_id, parent_id=None, children=[]): # pylint: disable=W0102 @@ -2929,10 +2892,8 @@ def setUp(self): 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) - - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() self.addCleanup(patcher.stop) def _get_oauth_headers(self, user): @@ -3223,6 +3184,9 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): super().setUp() + patcher = mock.patch('lms.djangoapps.discussion.toggles.ENABLE_FORUM_V2.is_enabled', return_value=False) + patcher.start() + self.addCleanup(patcher.stop) self.course = CourseFactory.create( org="x", course="y", @@ -3234,11 +3198,6 @@ def setUp(self): course_key = CourseKey.from_string('course-v1:x+y+z') seed_permissions_roles(course_key) - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() - self.addCleanup(patcher.stop) - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def path(self, course_id=None, role=None): """Return the URL path to the endpoint based on the provided arguments.""" @@ -3419,6 +3378,9 @@ 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('lms.djangoapps.discussion.toggles.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) @@ -3451,11 +3413,6 @@ def setUp(self) -> None: self.register_course_stats_response(self.course_key, self.stats, 1, 3) self.url = reverse("discussion_course_activity_stats", kwargs={"course_key_string": self.course_key}) - # Patch get_user for the entire class - patcher = mock.patch('openedx.core.djangoapps.django_comment_common.comment_client.user.forum_api.get_user') - self.mock_get_user = patcher.start() - self.addCleanup(patcher.stop) - @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def test_regular_user(self): """ diff --git a/lms/djangoapps/discussion/rest_api/tests/utils.py b/lms/djangoapps/discussion/rest_api/tests/utils.py index 0abff6b81b40..27e34705f5df 100644 --- a/lms/djangoapps/discussion/rest_api/tests/utils.py +++ b/lms/djangoapps/discussion/rest_api/tests/utils.py @@ -8,7 +8,6 @@ import re from contextlib import closing from datetime import datetime -from unittest import mock from urllib.parse import parse_qs import httpretty @@ -251,13 +250,18 @@ def register_get_comment_response(self, response_overrides): ) def register_get_user_response(self, user, subscribed_thread_ids=None, upvoted_ids=None): - """Register a mock response for the get_user method.""" - # Define the mock return value - self.mock_get_user.return_value = { - "id": str(user.id), - "subscribed_thread_ids": subscribed_thread_ids or [], - "upvoted_ids": upvoted_ids or [], - } + """Register a mock response for GET on the CS user instance endpoint""" + assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' + httpretty.register_uri( + httpretty.GET, + f"http://localhost:4567/api/v1/users/{user.id}", + body=json.dumps({ + "id": str(user.id), + "subscribed_thread_ids": subscribed_thread_ids or [], + "upvoted_ids": upvoted_ids or [], + }), + status=200 + ) def register_get_user_retire_response(self, user, status=200, body=""): """Register a mock response for GET on the CS user retirement endpoint""" diff --git a/lms/djangoapps/discussion/toggles.py b/lms/djangoapps/discussion/toggles.py index a1c292a4734f..6157e1ae862f 100644 --- a/lms/djangoapps/discussion/toggles.py +++ b/lms/djangoapps/discussion/toggles.py @@ -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,26 @@ # .. 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__ +) + +FORUM_V2_WAFFLE_FLAG_NAMESPACE = "forum_v2" + +# .. toggle_name: forum_v2.enable_forum_v2 +# .. toggle_implementation: CourseWaffleFlag +# .. toggle_default: False +# .. toggle_description: Waffle flag to use the forum v2 instead of v1(cs_comment_service) +# .. toggle_use_cases: temporary, open_edx +# .. toggle_creation_date: 2024-9-26 +# .. toggle_target_removal_date: 2025-12-05 +ENABLE_FORUM_V2 = CourseWaffleFlag( + f"{FORUM_V2_WAFFLE_FLAG_NAMESPACE}.enable_forum_v2", __name__ +) + + +def is_forum_v2_enabled(course_id): + """ + Returns a boolean if individualized anonymous_user_id is enabled on the course + """ + return ENABLE_FORUM_V2.is_enabled(course_id) diff --git a/openedx/core/djangoapps/django_comment_common/comment_client/course.py b/openedx/core/djangoapps/django_comment_common/comment_client/course.py index fc99664f211a..91f7a0e96a1d 100644 --- a/openedx/core/djangoapps/django_comment_common/comment_client/course.py +++ b/openedx/core/djangoapps/django_comment_common/comment_client/course.py @@ -8,6 +8,7 @@ from opaque_keys.edx.keys import CourseKey from forum import api as forum_api +from lms.djangoapps.discussion.toggles import is_forum_v2_enabled from openedx.core.djangoapps.django_comment_common.comment_client import settings from openedx.core.djangoapps.django_comment_common.comment_client.utils import perform_request @@ -30,7 +31,19 @@ def get_course_commentable_counts(course_key: CourseKey) -> Dict[str, Dict[str, } """ - commentable_stats = forum_api.get_commentables_stats(str(course_key)) + if is_forum_v2_enabled(course_key): + commentable_stats = forum_api.get_commentables_stats(str(course_key)) + else: + url = f"{settings.PREFIX}/commentables/{course_key}/counts" + commentable_stats = perform_request( + 'get', + url, + metric_tags=[ + f"course_key:{course_key}", + "function:get_course_commentable_counts", + ], + metric_action='commentable_stats.retrieve', + ) return commentable_stats diff --git a/openedx/core/djangoapps/django_comment_common/comment_client/models.py b/openedx/core/djangoapps/django_comment_common/comment_client/models.py index 67ec8b9ada52..9395ca43f50b 100644 --- a/openedx/core/djangoapps/django_comment_common/comment_client/models.py +++ b/openedx/core/djangoapps/django_comment_common/comment_client/models.py @@ -5,6 +5,7 @@ from .utils import CommentClientRequestError, extract, perform_request from forum import api as forum_api +from lms.djangoapps.discussion.toggles import is_forum_v2_enabled log = logging.getLogger(__name__) @@ -70,9 +71,11 @@ def retrieve(self, *args, **kwargs): return self def _retrieve(self, *args, **kwargs): - if self.type=="comment": - response = forum_api.get_parent_comment(self.attributes["id"]) - else: + response = None + if is_forum_v2_enabled(self.attributes.get("course_id")): + if self.type=="comment": + response = forum_api.get_parent_comment(self.attributes["id"]) + if response is None: url = self.url(action='get', params=self.attributes) response = perform_request( 'get', @@ -155,83 +158,20 @@ def save(self, params=None): """ self.before_save(self) if self.id: # if we have id already, treat this as an update - request_params = self.updatable_attributes() - if params: - request_params.update(params) - if self.type=="comment": - try: - body = request_params["body"] - course_id = str(request_params["course_id"]) - user_id = request_params["user_id"] - except KeyError as e: - raise e - response = forum_api.update_comment( - self.attributes["id"], - body, - course_id, - user_id, - request_params.get("anonymous", False), - request_params.get("anonymous_to_peers", False), - request_params.get("endorsed", False), - request_params.get("closed", False), - request_params.get("editing_user_id"), - request_params.get("edit_reason_code"), - request_params.get("endorsement_user_id"), - ) - else: - url = self.url(action='put', params=self.attributes) - response = perform_request( - 'put', - url, - request_params, - metric_tags=self._metric_tags, - metric_action='model.update' - ) + response = self.handle_update(params) else: # otherwise, treat this as an insert - if self.type=="comment": - request_data = self.initializable_attributes() - try: - body = request_data["body"] - user_id = request_data["user_id"] - course_id = str(request_data["course_id"]) - except KeyError as e: - raise e - if parent_id := self.attributes.get("parent_id"): - response = forum_api.create_child_comment( - parent_id, - body, - user_id, - course_id, - request_data.get("anonymous", False), - request_data.get("anonymous_to_peers", False), - ) - else: - response = forum_api.create_parent_comment( - self.attributes["thread_id"], - body, - user_id, - course_id, - request_data.get("anonymous", False), - request_data.get("anonymous_to_peers", False), - ) - else: # otherwise, treat this as an insert - url = self.url(action='post', params=self.attributes) - response = perform_request( - 'post', - url, - self.initializable_attributes(), - metric_tags=self._metric_tags, - metric_action='model.insert' - ) - + response = self.handle_create() + self.retrieved = True self._update_from_response(response) self.after_save(self) def delete(self): - if self.type=="comment": - response = forum_api.delete_comment(self.attributes["id"]) - else: + response = None + if is_forum_v2_enabled(self.attributes.get("course_id")): + if self.type=="comment": + response = forum_api.delete_comment(self.attributes["id"]) + if response is None: url = self.url(action='delete', params=self.attributes) response = perform_request('delete', url, metric_tags=self._metric_tags, metric_action='model.delete') self.retrieved = True @@ -264,3 +204,96 @@ def url(cls, action, params=None): raise CommentClientRequestError(f"Cannot perform action {action} without id") # lint-amnesty, pylint: disable=raise-missing-from else: # action must be in DEFAULT_ACTIONS_WITHOUT_ID now return cls.url_without_id() + + def handle_update(self, params=None): + request_params = self.updatable_attributes() + if params: + request_params.update(params) + response = None + if is_forum_v2_enabled(request_params.get("course_id")): + if self.type == "comment": + response = self.handle_update_comment(request_params) + if response is None: + response = self.perform_http_put_request(request_params) + return response + + def handle_update_comment(self, request_params): + try: + body = request_params["body"] + course_id = str(request_params["course_id"]) + user_id = request_params["user_id"] + except KeyError as e: + raise e + response = forum_api.update_comment( + self.attributes["id"], + body, + course_id, + user_id, + request_params.get("anonymous", False), + request_params.get("anonymous_to_peers", False), + request_params.get("endorsed", False), + request_params.get("closed", False), + request_params.get("editing_user_id"), + request_params.get("edit_reason_code"), + request_params.get("endorsement_user_id"), + ) + return response + + def perform_http_put_request(self, request_params): + url = self.url(action="put", params=self.attributes) + response = perform_request( + "put", + url, + request_params, + metric_tags=self._metric_tags, + metric_action="model.update", + ) + return response + + def perform_http_post_request(self): + url = self.url(action="post", params=self.attributes) + response = perform_request( + "post", + url, + self.initializable_attributes(), + metric_tags=self._metric_tags, + metric_action="model.insert", + ) + return response + + def handle_create(self): + response = None + if is_forum_v2_enabled(self.attributes.get("course_id")): + if self.type == "comment": + response = self.handle_create_comment() + if response is None: + response = self.perform_http_post_request() + return response + + def handle_create_comment(self): + request_data = self.initializable_attributes() + try: + body = request_data["body"] + user_id = request_data["user_id"] + course_id = str(request_data["course_id"]) + except KeyError as e: + raise e + if parent_id := self.attributes.get("parent_id"): + response = forum_api.create_child_comment( + parent_id, + body, + user_id, + course_id, + request_data.get("anonymous", False), + request_data.get("anonymous_to_peers", False), + ) + else: + response = forum_api.create_parent_comment( + self.attributes["thread_id"], + body, + user_id, + course_id, + request_data.get("anonymous", False), + request_data.get("anonymous_to_peers", False), + ) + return response diff --git a/openedx/core/djangoapps/django_comment_common/comment_client/thread.py b/openedx/core/djangoapps/django_comment_common/comment_client/thread.py index a5be67ffbf97..f518b390b259 100644 --- a/openedx/core/djangoapps/django_comment_common/comment_client/thread.py +++ b/openedx/core/djangoapps/django_comment_common/comment_client/thread.py @@ -7,6 +7,7 @@ from . import models, settings, utils from forum import api as forum_api +from lms.djangoapps.discussion.toggles import is_forum_v2_enabled log = logging.getLogger(__name__) @@ -194,12 +195,34 @@ def unFlagAbuse(self, user, voteable, removeAll): voteable._update_from_response(response) def pin(self, user, thread_id): - thread_data = forum_api.pin_thread(user.id, thread_id) - self._update_from_response(thread_data) + if is_forum_v2_enabled(self.attributes.get("course_id")): + response = forum_api.pin_thread(user.id, thread_id) + else: + url = _url_for_pin_thread(thread_id) + params = {'user_id': user.id} + response = utils.perform_request( + 'put', + url, + params, + metric_tags=self._metric_tags, + metric_action='thread.pin' + ) + self._update_from_response(response) def un_pin(self, user, thread_id): - thread_data = forum_api.unpin_thread(user.id, thread_id) - self._update_from_response(thread_data) + if is_forum_v2_enabled(self.attributes.get("course_id")): + response = forum_api.unpin_thread(user.id, thread_id) + else: + url = _url_for_un_pin_thread(thread_id) + params = {'user_id': user.id} + response = utils.perform_request( + 'put', + url, + params, + metric_tags=self._metric_tags, + metric_action='thread.unpin' + ) + self._update_from_response(response) def _url_for_flag_abuse_thread(thread_id): @@ -208,3 +231,11 @@ def _url_for_flag_abuse_thread(thread_id): def _url_for_unflag_abuse_thread(thread_id): return f"{settings.PREFIX}/threads/{thread_id}/abuse_unflag" + + +def _url_for_pin_thread(thread_id): + return f"{settings.PREFIX}/threads/{thread_id}/pin" + + +def _url_for_un_pin_thread(thread_id): + return f"{settings.PREFIX}/threads/{thread_id}/unpin" diff --git a/openedx/core/djangoapps/django_comment_common/comment_client/user.py b/openedx/core/djangoapps/django_comment_common/comment_client/user.py index f280db90c72e..bc0362e505e8 100644 --- a/openedx/core/djangoapps/django_comment_common/comment_client/user.py +++ b/openedx/core/djangoapps/django_comment_common/comment_client/user.py @@ -4,6 +4,7 @@ from . import models, settings, utils from forum import api as forum_api +from lms.djangoapps.discussion.toggles import is_forum_v2_enabled class User(models.Model): @@ -145,10 +146,35 @@ def _retrieve(self, *args, **kwargs): retrieve_params = self.default_retrieve_params.copy() retrieve_params.update(kwargs) if self.attributes.get('course_id'): - retrieve_params['course_id'] = str(self.course_id) + retrieve_params['course_id'] = str(self.attributes["course_id"]) if self.attributes.get('group_id'): - retrieve_params['group_id'] = self.group_id - response = forum_api.get_user(self.attributes["id"], retrieve_params) + retrieve_params['group_id'] = self.attributes["group_id"] + if is_forum_v2_enabled(self.attributes.get("course_id")): + response = forum_api.get_user(self.attributes["id"], retrieve_params) + else: + url = self.url(action='get', params=self.attributes) + try: + response = utils.perform_request( + 'get', + url, + retrieve_params, + metric_action='model.retrieve', + metric_tags=self._metric_tags, + ) + except utils.CommentClientRequestError as e: + if e.status_code == 404: + # attempt to gracefully recover from a previous failure + # to sync this user to the comments service. + self.save() + response = utils.perform_request( + 'get', + url, + retrieve_params, + metric_action='model.retrieve', + metric_tags=self._metric_tags, + ) + else: + raise self._update_from_response(response) def retire(self, retired_username):