Skip to content

Commit c824903

Browse files
Ali-Salman29ormsbee
authored andcommitted
feat!: remove cs_comments_service support for forum's vote APIs
This will force the use of the new v2 forum's APIs for voting/unvoting.
1 parent 0721460 commit c824903

7 files changed

Lines changed: 489 additions & 399 deletions

File tree

lms/djangoapps/discussion/django_comment_client/base/tests.py

Lines changed: 1 addition & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -191,17 +191,6 @@ def test_delete(self, mock_is_forum_v2_enabled, mock_request):
191191
response = self.call_view("delete_thread", mock_is_forum_v2_enabled, mock_request)
192192
self._assert_json_response_contains_group_info(response)
193193

194-
def test_vote(self, mock_is_forum_v2_enabled, mock_request):
195-
response = self.call_view(
196-
"vote_for_thread",
197-
mock_is_forum_v2_enabled,
198-
mock_request,
199-
view_args={"value": "up"}
200-
)
201-
self._assert_json_response_contains_group_info(response)
202-
response = self.call_view("undo_vote_for_thread", mock_is_forum_v2_enabled, mock_request)
203-
self._assert_json_response_contains_group_info(response)
204-
205194
def test_openclose(self, mock_is_forum_v2_enabled, mock_request):
206195
response = self.call_view(
207196
"openclose_thread",
@@ -791,25 +780,6 @@ def test_update_comment_basic(self, mock_is_forum_v2_enabled, mock_request):
791780
data={"body": updated_body, "course_id": str(self.course_id)}
792781
)
793782

794-
@ddt.data(
795-
('upvote_thread', 'thread_id', 'thread_voted'),
796-
('upvote_comment', 'comment_id', 'comment_voted'),
797-
('downvote_thread', 'thread_id', 'thread_voted'),
798-
('downvote_comment', 'comment_id', 'comment_voted')
799-
)
800-
@ddt.unpack
801-
def test_voting(self, view_name, item_id, signal, mock_is_forum_v2_enabled, mock_request):
802-
mock_is_forum_v2_enabled.return_value = False
803-
self._setup_mock_request(mock_request)
804-
with self.assert_discussion_signals(signal):
805-
response = self.client.post(
806-
reverse(
807-
view_name,
808-
kwargs={item_id: 'dummy', 'course_id': str(self.course_id)}
809-
)
810-
)
811-
assert response.status_code == 200
812-
813783
def test_endorse_comment(self, mock_is_forum_v2_enabled, mock_request):
814784
mock_is_forum_v2_enabled.return_value = False
815785
self._setup_mock_request(mock_request)
@@ -1451,33 +1421,6 @@ def test_create_sub_comment(self, user, commentable_id, status_code, mock_is_for
14511421
)
14521422
assert response.status_code == status_code
14531423

1454-
@ddt.data(*ddt_permissions_args)
1455-
@ddt.unpack
1456-
def test_comment_actions(self, user, commentable_id, status_code, mock_is_forum_v2_enabled, mock_request):
1457-
"""
1458-
Verify that voting and flagging of comments is limited to members of the team or users with
1459-
'edit_content' permission.
1460-
"""
1461-
commentable_id = getattr(self, commentable_id)
1462-
self._setup_mock(
1463-
user, mock_is_forum_v2_enabled, mock_request,
1464-
{
1465-
"closed": False,
1466-
"commentable_id": commentable_id,
1467-
"thread_id": "dummy_thread",
1468-
"body": 'dummy body',
1469-
"course_id": str(self.course.id)
1470-
},
1471-
)
1472-
for action in ["upvote_comment", "downvote_comment"]:
1473-
response = self.client.post(
1474-
reverse(
1475-
action,
1476-
kwargs={"course_id": str(self.course.id), "comment_id": "dummy_comment"}
1477-
)
1478-
)
1479-
assert response.status_code == status_code
1480-
14811424
@ddt.data(*ddt_permissions_args)
14821425
@ddt.unpack
14831426
def test_threads_actions(self, user, commentable_id, status_code, mock_is_forum_v2_enabled, mock_request):
@@ -1490,7 +1433,7 @@ def test_threads_actions(self, user, commentable_id, status_code, mock_is_forum_
14901433
user, mock_is_forum_v2_enabled, mock_request,
14911434
{"closed": False, "commentable_id": commentable_id, "body": "dummy body", "course_id": str(self.course.id)}
14921435
)
1493-
for action in ["upvote_thread", "downvote_thread", "follow_thread", "unfollow_thread"]:
1436+
for action in ["follow_thread", "unfollow_thread"]:
14941437
response = self.client.post(
14951438
reverse(
14961439
action,
@@ -1690,42 +1633,6 @@ def test_team_events(self, view_name, event_name, view_data, view_kwargs, mock_i
16901633
event_receiver.call_args.kwargs
16911634
)
16921635

1693-
@ddt.data(
1694-
('vote_for_thread', 'thread_id', 'thread'),
1695-
('undo_vote_for_thread', 'thread_id', 'thread'),
1696-
('vote_for_comment', 'comment_id', 'response'),
1697-
('undo_vote_for_comment', 'comment_id', 'response'),
1698-
)
1699-
@ddt.unpack
1700-
@patch('eventtracking.tracker.emit')
1701-
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)
1702-
@patch('openedx.core.djangoapps.discussions.config.waffle.ENABLE_FORUM_V2.is_enabled', autospec=True)
1703-
def test_thread_voted_event(self, view_name, obj_id_name, obj_type, mock_is_forum_v2_enabled, mock_request, mock_emit):
1704-
undo = view_name.startswith('undo')
1705-
1706-
mock_is_forum_v2_enabled.return_value = False
1707-
self._set_mock_request_data(mock_request, {
1708-
'closed': False,
1709-
'commentable_id': 'test_commentable_id',
1710-
'username': 'gumprecht',
1711-
})
1712-
request = RequestFactory().post('dummy_url', {})
1713-
request.user = self.student
1714-
request.view_name = view_name
1715-
view_function = getattr(views, view_name)
1716-
kwargs = dict(course_id=str(self.course.id))
1717-
kwargs[obj_id_name] = obj_id_name
1718-
if not undo:
1719-
kwargs.update(value='up')
1720-
view_function(request, **kwargs)
1721-
1722-
assert mock_emit.called
1723-
event_name, event = mock_emit.call_args[0]
1724-
assert event_name == f'edx.forum.{obj_type}.voted'
1725-
assert event['target_username'] == 'gumprecht'
1726-
assert event['undo_vote'] == undo
1727-
assert event['vote_value'] == 'up'
1728-
17291636
@ddt.data('follow_thread', 'unfollow_thread',)
17301637
@patch('eventtracking.tracker.emit')
17311638
@patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True)

lms/djangoapps/discussion/django_comment_client/base/tests_v2.py

Lines changed: 149 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ def test_pin_thread(self):
155155
assert response.status_code == 200
156156
self._assert_json_response_contains_group_info(response)
157157

158+
def test_vote(self):
159+
response = self.call_view(
160+
"vote_for_thread", "update_thread_votes", view_args={"value": "up"}
161+
)
162+
self._assert_json_response_contains_group_info(response)
163+
response = self.call_view("undo_vote_for_thread", "delete_thread_vote")
164+
self._assert_json_response_contains_group_info(response)
165+
158166

159167
class ViewsTestCaseMixin:
160168

@@ -214,6 +222,22 @@ def set_up_course(self, block_count=0):
214222

215223
assert self.client.login(username="student", password=self.password)
216224

225+
def _setup_mock_request(self, mock_function, include_depth=False):
226+
"""
227+
Ensure that mock_request returns the data necessary to make views
228+
function correctly
229+
"""
230+
data = {
231+
"user_id": str(self.student.id),
232+
"closed": False,
233+
"commentable_id": "non_team_dummy_id",
234+
"thread_id": "dummy",
235+
"thread_type": "discussion",
236+
}
237+
if include_depth:
238+
data["depth"] = 0
239+
self.set_mock_return_value(mock_function, data)
240+
217241

218242
@ddt.ddt
219243
@disable_signal(views, "comment_flagged")
@@ -549,6 +573,26 @@ def un_flag_comment(self, is_closed):
549573

550574
assert response.status_code == 200
551575

576+
@ddt.data(
577+
("upvote_thread", "update_thread_votes", "thread_id", "thread_voted"),
578+
("upvote_comment", "update_comment_votes", "comment_id", "comment_voted"),
579+
("downvote_thread", "update_thread_votes", "thread_id", "thread_voted"),
580+
("downvote_comment", "update_comment_votes", "comment_id", "comment_voted"),
581+
)
582+
@ddt.unpack
583+
def test_voting(self, view_name, function_name, item_id, signal):
584+
self._setup_mock_request("get_thread")
585+
self._setup_mock_request("get_parent_comment")
586+
self._setup_mock_request(function_name)
587+
with self.assert_discussion_signals(signal):
588+
response = self.client.post(
589+
reverse(
590+
view_name,
591+
kwargs={item_id: "dummy", "course_id": str(self.course_id)},
592+
)
593+
)
594+
assert response.status_code == 200
595+
552596

553597
@disable_signal(views, "comment_endorsed")
554598
class ViewPermissionsTestCase(
@@ -843,15 +887,22 @@ def test_comment_actions(self, user, commentable_id, status_code):
843887
commentable_id = getattr(self, commentable_id)
844888
self._setup_mock(
845889
user,
846-
["get_parent_comment", "update_comment_flag"],
890+
[
891+
"get_parent_comment",
892+
"update_comment_flag",
893+
"update_comment_votes",
894+
"delete_comment_vote",
895+
],
847896
make_minimal_cs_comment(
848897
{
898+
"closed": False,
849899
"commentable_id": commentable_id,
850900
"course_id": str(self.course.id),
851901
}
852902
),
853903
)
854-
for action in ["un_flag_abuse_for_comment", "flag_abuse_for_comment"]:
904+
# "un_flag_abuse_for_comment", "flag_abuse_for_comment",
905+
for action in ["upvote_comment", "downvote_comment"]:
855906
response = self.client.post(
856907
reverse(
857908
action,
@@ -873,7 +924,12 @@ def test_threads_actions(self, user, commentable_id, status_code):
873924
commentable_id = getattr(self, commentable_id)
874925
self._setup_mock(
875926
user,
876-
["get_thread", "update_thread_flag"],
927+
[
928+
"get_thread",
929+
"update_thread_flag",
930+
"update_thread_votes",
931+
"delete_thread_vote",
932+
],
877933
make_minimal_cs_thread(
878934
{
879935
"commentable_id": commentable_id,
@@ -882,7 +938,12 @@ def test_threads_actions(self, user, commentable_id, status_code):
882938
),
883939
)
884940

885-
for action in ["un_flag_abuse_for_thread", "flag_abuse_for_thread"]:
941+
for action in [
942+
"un_flag_abuse_for_thread",
943+
"flag_abuse_for_thread",
944+
"upvote_thread",
945+
"downvote_thread",
946+
]:
886947
response = self.client.post(
887948
reverse(
888949
action,
@@ -893,3 +954,87 @@ def test_threads_actions(self, user, commentable_id, status_code):
893954
)
894955
)
895956
assert response.status_code == status_code
957+
958+
959+
@disable_signal(views, "comment_created")
960+
@ddt.ddt
961+
class ForumEventTestCase(
962+
ForumsEnableMixin, SharedModuleStoreTestCase, MockForumApiMixin
963+
):
964+
"""
965+
Forum actions are expected to launch analytics events. Test these here.
966+
"""
967+
968+
@classmethod
969+
def setUpClass(cls):
970+
super().setUpClassAndForumMock()
971+
# pylint: disable=super-method-not-called
972+
with super().setUpClassAndTestData():
973+
cls.course = CourseFactory.create()
974+
975+
@classmethod
976+
def tearDownClass(cls):
977+
"""Stop patches after tests complete."""
978+
super().tearDownClass()
979+
super().disposeForumMocks()
980+
981+
@classmethod
982+
def setUpTestData(cls):
983+
super().setUpTestData()
984+
985+
seed_permissions_roles(cls.course.id)
986+
987+
cls.student = UserFactory.create()
988+
CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id)
989+
cls.student.roles.add(Role.objects.get(name="Student", course_id=cls.course.id))
990+
CourseAccessRoleFactory(
991+
course_id=cls.course.id, user=cls.student, role="Wizard"
992+
)
993+
994+
@ddt.data(
995+
("vote_for_thread", "update_thread_votes", "thread_id", "thread"),
996+
("undo_vote_for_thread", "delete_thread_vote", "thread_id", "thread"),
997+
("vote_for_comment", "update_comment_votes", "comment_id", "response"),
998+
("undo_vote_for_comment", "delete_comment_vote", "comment_id", "response"),
999+
)
1000+
@ddt.unpack
1001+
@patch("eventtracking.tracker.emit")
1002+
def test_thread_voted_event(
1003+
self, view_name, function_name, obj_id_name, obj_type, mock_emit
1004+
):
1005+
undo = view_name.startswith("undo")
1006+
cs_thread = make_minimal_cs_thread(
1007+
{
1008+
"commentable_id": "test_commentable_id",
1009+
"username": "gumprecht",
1010+
}
1011+
)
1012+
cs_comment = make_minimal_cs_comment(
1013+
{
1014+
"closed": False,
1015+
"commentable_id": "test_commentable_id",
1016+
"username": "gumprecht",
1017+
}
1018+
)
1019+
self.set_mock_return_value("get_thread", cs_thread)
1020+
self.set_mock_return_value("get_parent_comment", cs_comment)
1021+
self.set_mock_return_value(
1022+
function_name, cs_thread if "thread" in view_name else cs_comment
1023+
)
1024+
1025+
request = RequestFactory().post("dummy_url", {})
1026+
request.user = self.student
1027+
request.view_name = view_name
1028+
view_function = getattr(views, view_name)
1029+
kwargs = dict(course_id=str(self.course.id))
1030+
kwargs[obj_id_name] = obj_id_name
1031+
if not undo:
1032+
kwargs.update(value="up")
1033+
view_function(request, **kwargs)
1034+
1035+
assert mock_emit.called
1036+
event_name, event = mock_emit.call_args[0]
1037+
assert event_name == f"edx.forum.{obj_type}.voted"
1038+
assert event["target_username"] == "gumprecht"
1039+
assert event["undo_vote"] == undo
1040+
assert event["vote_value"] == "up"

lms/djangoapps/discussion/django_comment_client/tests/mixins.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
class MockForumApiMixin:
99
"""Mixin to mock forum_api across different test cases with a single mock instance."""
1010

11+
users_map = {}
12+
1113
@classmethod
1214
def setUpClassAndForumMock(cls):
1315
"""

0 commit comments

Comments
 (0)