@@ -241,3 +241,219 @@ def test_team_discussion_id_not_cohorted(self, mock_is_forum_v2_enabled, mock_re
241241 self .call_view (mock_is_forum_v2_enabled , mock_request , team .discussion_topic_id , self .student , '' )
242242
243243 self ._assert_comments_service_called_without_group_id (mock_request )
244+
245+
246+ class GroupIdAssertionMixinV2 :
247+ """
248+ Provides assertion methods for testing group_id functionality in forum v2.
249+
250+ This mixin contains helper methods to verify that the comments service is called
251+ with the correct group_id parameters and that responses contain the expected
252+ group information.
253+ """
254+ def _get_params_last_call (self , function_name ):
255+ """
256+ Returns the data or params dict that `mock_request` was called with.
257+ """
258+ return self .get_mock_func_calls (function_name )[- 1 ][1 ]
259+
260+ def _assert_comments_service_called_with_group_id (self , group_id ):
261+ assert self .check_mock_called ('get_user_threads' )
262+ assert self ._get_params_last_call ('get_user_threads' )['group_id' ] == group_id
263+
264+ def _assert_comments_service_called_without_group_id (self ):
265+ assert self .check_mock_called ('get_user_threads' )
266+ assert 'group_id' not in self ._get_params_last_call ('get_user_threads' )
267+
268+ def _assert_html_response_contains_group_info (self , response ):
269+ group_info = {"group_id" : None , "group_name" : None }
270+ match = re .search (r'"group_id": (\d*),' , response .content .decode ('utf-8' ))
271+ if match and match .group (1 ) != '' :
272+ group_info ["group_id" ] = int (match .group (1 ))
273+ match = re .search (r'"group_name": "(\w*)"' , response .content .decode ('utf-8' ))
274+ if match :
275+ group_info ["group_name" ] = match .group (1 )
276+ self ._assert_thread_contains_group_info (group_info )
277+
278+ def _assert_json_response_contains_group_info (self , response , extract_thread = None ):
279+ """
280+ :param extract_thread: a function which accepts a dictionary (complete
281+ json response payload) and returns another dictionary (first
282+ occurrence of a thread model within that payload). if None is
283+ passed, the identity function is assumed.
284+ """
285+ payload = json .loads (response .content .decode ('utf-8' ))
286+ thread = extract_thread (payload ) if extract_thread else payload
287+ self ._assert_thread_contains_group_info (thread )
288+
289+ def _assert_thread_contains_group_info (self , thread ):
290+ assert thread ['group_id' ] == self .student_cohort .id
291+ assert thread ['group_name' ] == self .student_cohort .name
292+
293+
294+ class CohortedTopicGroupIdTestMixinV2 (GroupIdAssertionMixinV2 ):
295+ """
296+ Provides test cases to verify that views pass the correct `group_id` to
297+ the comments service when requesting content in cohorted discussions for forum v2.
298+ """
299+ def call_view (self , commentable_id , user , group_id , pass_group_id = True ):
300+ """
301+ Call the view for the implementing test class, constructing a request
302+ from the parameters.
303+ """
304+ pass # lint-amnesty, pylint: disable=unnecessary-pass
305+
306+ def test_cohorted_topic_student_without_group_id (self ):
307+ self .call_view ("cohorted_topic" , self .student , '' , pass_group_id = False )
308+ self ._assert_comments_service_called_with_group_id (self .student_cohort .id )
309+
310+ def test_cohorted_topic_student_none_group_id (self ):
311+ self .call_view ("cohorted_topic" , self .student , "" )
312+ self ._assert_comments_service_called_with_group_id (self .student_cohort .id )
313+
314+ def test_cohorted_topic_student_with_own_group_id (self ):
315+ self .call_view ("cohorted_topic" , self .student , self .student_cohort .id )
316+ self ._assert_comments_service_called_with_group_id (self .student_cohort .id )
317+
318+ def test_cohorted_topic_student_with_other_group_id (self ):
319+ self .call_view (
320+ "cohorted_topic" ,
321+ self .student ,
322+ self .moderator_cohort .id
323+ )
324+ self ._assert_comments_service_called_with_group_id (self .student_cohort .id )
325+
326+ def test_cohorted_topic_moderator_without_group_id (self ):
327+ self .call_view (
328+ "cohorted_topic" ,
329+ self .moderator ,
330+ '' ,
331+ pass_group_id = False
332+ )
333+ self ._assert_comments_service_called_without_group_id ()
334+
335+ def test_cohorted_topic_moderator_none_group_id (self ):
336+ self .call_view ("cohorted_topic" , self .moderator , "" )
337+ self ._assert_comments_service_called_without_group_id ()
338+
339+ def test_cohorted_topic_moderator_with_own_group_id (self ):
340+ self .call_view (
341+ "cohorted_topic" ,
342+ self .moderator ,
343+ self .moderator_cohort .id
344+ )
345+ self ._assert_comments_service_called_with_group_id (self .moderator_cohort .id )
346+
347+ def test_cohorted_topic_moderator_with_other_group_id (self ):
348+ self .call_view (
349+ "cohorted_topic" ,
350+ self .moderator ,
351+ self .student_cohort .id
352+ )
353+ self ._assert_comments_service_called_with_group_id (self .student_cohort .id )
354+
355+ def test_cohorted_topic_moderator_with_invalid_group_id (self ):
356+ invalid_id = self .student_cohort .id + self .moderator_cohort .id
357+ response = self .call_view ("cohorted_topic" , self .moderator , invalid_id ) # lint-amnesty, pylint: disable=assignment-from-no-return
358+ assert response .status_code == 500
359+
360+ def test_cohorted_topic_enrollment_track_invalid_group_id (self ):
361+ CourseModeFactory .create (course_id = self .course .id , mode_slug = CourseMode .AUDIT )
362+ CourseModeFactory .create (course_id = self .course .id , mode_slug = CourseMode .VERIFIED )
363+ discussion_settings = CourseDiscussionSettings .get (self .course .id )
364+ discussion_settings .update ({
365+ 'divided_discussions' : ['cohorted_topic' ],
366+ 'division_scheme' : CourseDiscussionSettings .ENROLLMENT_TRACK ,
367+ 'always_divide_inline_discussions' : True ,
368+ })
369+
370+ invalid_id = - 1000
371+ response = self .call_view ("cohorted_topic" , self .moderator , invalid_id ) # lint-amnesty, pylint: disable=assignment-from-no-return
372+ assert response .status_code == 500
373+
374+
375+ class NonCohortedTopicGroupIdTestMixinV2 (GroupIdAssertionMixinV2 ):
376+ """
377+ Provides test cases to verify that views pass the correct `group_id` to
378+ the comments service when requesting content in non-cohorted discussions for forum v2.
379+ """
380+ def call_view (self , commentable_id , user , group_id , pass_group_id = True ):
381+ """
382+ Call the view for the implementing test class, constructing a request
383+ from the parameters.
384+ """
385+ pass # lint-amnesty, pylint: disable=unnecessary-pass
386+
387+ def test_non_cohorted_topic_student_without_group_id (self ):
388+ self .call_view (
389+ "non_cohorted_topic" ,
390+ self .student ,
391+ '' ,
392+ pass_group_id = False
393+ )
394+ self ._assert_comments_service_called_without_group_id ()
395+
396+ def test_non_cohorted_topic_student_none_group_id (self ):
397+ self .call_view ("non_cohorted_topic" , self .student , '' )
398+ self ._assert_comments_service_called_without_group_id ()
399+
400+ def test_non_cohorted_topic_student_with_own_group_id (self ):
401+ self .call_view (
402+ "non_cohorted_topic" ,
403+ self .student ,
404+ self .student_cohort .id
405+ )
406+ self ._assert_comments_service_called_without_group_id ()
407+
408+ def test_non_cohorted_topic_student_with_other_group_id (self ):
409+ self .call_view (
410+ "non_cohorted_topic" ,
411+ self .student ,
412+ self .moderator_cohort .id
413+ )
414+ self ._assert_comments_service_called_without_group_id ()
415+
416+ def test_non_cohorted_topic_moderator_without_group_id (self ):
417+ self .call_view (
418+ "non_cohorted_topic" ,
419+ self .moderator ,
420+ "" ,
421+ pass_group_id = False ,
422+ )
423+ self ._assert_comments_service_called_without_group_id ()
424+
425+ def test_non_cohorted_topic_moderator_none_group_id (self ):
426+ self .call_view ("non_cohorted_topic" , self .moderator , '' )
427+ self ._assert_comments_service_called_without_group_id ()
428+
429+ def test_non_cohorted_topic_moderator_with_own_group_id (self ):
430+ self .call_view (
431+ "non_cohorted_topic" ,
432+ self .moderator ,
433+ self .moderator_cohort .id ,
434+ )
435+ self ._assert_comments_service_called_without_group_id ()
436+
437+ def test_non_cohorted_topic_moderator_with_other_group_id (self ):
438+ self .call_view (
439+ "non_cohorted_topic" ,
440+ self .moderator ,
441+ self .student_cohort .id ,
442+ )
443+ self ._assert_comments_service_called_without_group_id ()
444+
445+ def test_non_cohorted_topic_moderator_with_invalid_group_id (self ):
446+ invalid_id = self .student_cohort .id + self .moderator_cohort .id
447+ self .call_view ("non_cohorted_topic" , self .moderator , invalid_id )
448+ self ._assert_comments_service_called_without_group_id ()
449+
450+ def test_team_discussion_id_not_cohorted (self ):
451+ team = CourseTeamFactory (
452+ course_id = self .course .id ,
453+ topic_id = 'topic-id'
454+ )
455+
456+ team .add_user (self .student )
457+ self .call_view (team .discussion_topic_id , self .student , '' )
458+
459+ self ._assert_comments_service_called_without_group_id ()
0 commit comments