Repository: openfun/marsha

Issue:
Start and stop recording API is not dispatching message in the websocket
## Bug Report

**Expected behavior/code**

When an instructor start or stop recording a live, all other participant (student and instructor) should be aware of this action.

**Actual Behavior**

Only the instructor doing the action have the new serialized video in the request response

**Steps to Reproduce**
1. Configure a webinar
2. Connect multiple instructors to this webinar
3. Start streaming
4. When streaming, start recording
5. Nobody else is aware that the live is recording


**Possible Solution**

Dispatch the new video object in the websocket to all participants.





Discussion:

Resolving patch:
diff --git a/src/backend/marsha/core/api/video.py b/src/backend/marsha/core/api/video.py
--- a/src/backend/marsha/core/api/video.py
+++ b/src/backend/marsha/core/api/video.py
@@ -857,6 +857,9 @@ def start_recording(
             start_recording(video)
         except VideoRecordingError as error:
             return Response({"detail": str(error)}, status=400)
+
+        channel_layers_utils.dispatch_video_to_groups(video)
+
         serializer = self.get_serializer(video)
         return Response(serializer.data)
 
@@ -894,5 +897,8 @@ def stop_recording(
             stop_recording(video)
         except VideoRecordingError as error:
             return Response({"detail": str(error)}, status=400)
+
+        channel_layers_utils.dispatch_video_to_groups(video)
+
         serializer = self.get_serializer(video)
         return Response(serializer.data)


Test patch:
diff --git a/src/backend/marsha/core/tests/test_api_video_recording.py b/src/backend/marsha/core/tests/test_api_video_recording.py
--- a/src/backend/marsha/core/tests/test_api_video_recording.py
+++ b/src/backend/marsha/core/tests/test_api_video_recording.py
@@ -158,7 +158,9 @@ def test_api_video_recording_start_instructor(self):
         now = timezone.now()
         with mock.patch.object(timezone, "now", return_value=now), mock.patch(
             "marsha.core.serializers.xmpp_utils.generate_jwt"
-        ) as mock_jwt_encode:
+        ) as mock_jwt_encode, mock.patch(
+            "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups"
+        ) as mock_dispatch_video_to_groups:
             mock_jwt_encode.return_value = "xmpp_jwt"
             response = self.client.patch(
                 f"/api/videos/{video.id}/start-recording/",
@@ -166,6 +168,7 @@ def test_api_video_recording_start_instructor(self):
             )
         video.refresh_from_db()
 
+        mock_dispatch_video_to_groups.assert_called_once_with(video)
         self.assertEqual(response.status_code, 200)
 
         content = response.json()
@@ -284,7 +287,9 @@ def test_api_video_recording_start_not_allowed(self):
         now = timezone.now()
         with mock.patch.object(timezone, "now", return_value=now), mock.patch(
             "marsha.core.serializers.xmpp_utils.generate_jwt"
-        ) as mock_jwt_encode:
+        ) as mock_jwt_encode, mock.patch(
+            "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups"
+        ) as mock_dispatch_video_to_groups:
             mock_jwt_encode.return_value = "xmpp_jwt"
             response = self.client.patch(
                 f"/api/videos/{video.id}/start-recording/",
@@ -292,6 +297,8 @@ def test_api_video_recording_start_not_allowed(self):
             )
         video.refresh_from_db()
 
+        mock_dispatch_video_to_groups.assert_not_called()
+
         self.assertEqual(response.status_code, 400)
 
         content = response.json()
@@ -346,7 +353,9 @@ def test_api_video_recording_start_live_not_running(self):
         now = timezone.now()
         with mock.patch.object(timezone, "now", return_value=now), mock.patch(
             "marsha.core.serializers.xmpp_utils.generate_jwt"
-        ) as mock_jwt_encode:
+        ) as mock_jwt_encode, mock.patch(
+            "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups"
+        ) as mock_dispatch_video_to_groups:
             mock_jwt_encode.return_value = "xmpp_jwt"
             response = self.client.patch(
                 f"/api/videos/{video.id}/start-recording/",
@@ -354,6 +363,8 @@ def test_api_video_recording_start_live_not_running(self):
             )
         video.refresh_from_db()
 
+        mock_dispatch_video_to_groups.assert_not_called()
+
         self.assertEqual(response.status_code, 400)
 
         content = response.json()
@@ -409,7 +420,9 @@ def test_api_video_recording_stop_instructor_started_slice(self):
 
         with mock.patch.object(timezone, "now", return_value=stop), mock.patch(
             "marsha.core.serializers.xmpp_utils.generate_jwt"
-        ) as mock_jwt_encode:
+        ) as mock_jwt_encode, mock.patch(
+            "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups"
+        ) as mock_dispatch_video_to_groups:
             mock_jwt_encode.return_value = "xmpp_jwt"
             response = self.client.patch(
                 f"/api/videos/{video.id}/stop-recording/",
@@ -418,6 +431,10 @@ def test_api_video_recording_stop_instructor_started_slice(self):
 
         self.assertEqual(response.status_code, 200)
 
+        video.refresh_from_db()
+
+        mock_dispatch_video_to_groups.assert_called_once_with(video)
+
         content = response.json()
         self.assertEqual(
             content,