diff --git a/CHANGELOG.md b/CHANGELOG.md index b87bcc4241..ec6d5f37f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed + +- Authorize ended live to initiate a transcription + ## [5.4.0] - 2024-11-13 ### Changed diff --git a/src/backend/marsha/core/api/video.py b/src/backend/marsha/core/api/video.py index 30b921514a..1b6c94cbb7 100644 --- a/src/backend/marsha/core/api/video.py +++ b/src/backend/marsha/core/api/video.py @@ -1215,7 +1215,7 @@ def initiate_transcript(self, request, pk=None): """Initiate the transcript process for the video.""" video = self.get_object() - if video.live_state is not None: + if video.live_state and video.live_state != defaults.ENDED: return Response( {"detail": "Cannot initiate transcript on a live video"}, status=HTTPStatus.BAD_REQUEST, diff --git a/src/backend/marsha/core/tests/api/video/test_initiate_transcript.py b/src/backend/marsha/core/tests/api/video/test_initiate_transcript.py index 7dc33d8556..582a1a1f7f 100644 --- a/src/backend/marsha/core/tests/api/video/test_initiate_transcript.py +++ b/src/backend/marsha/core/tests/api/video/test_initiate_transcript.py @@ -3,6 +3,7 @@ from datetime import datetime, timezone as baseTimezone from http import HTTPStatus import json +import random from unittest import mock from django.db.transaction import atomic @@ -49,6 +50,23 @@ def test_api_video_instructor_initiate_transcript_in_read_only(self): self.assertEqual(response.status_code, HTTPStatus.FORBIDDEN) + def test_api_video_instructor_initiate_transcript_for_live_video(self): + """A video in a live state can not initiate a transcription.""" + video = factories.VideoFactory( + live_type=defaults.JITSI, + live_state=random.choice( + [s[0] for s in defaults.LIVE_CHOICES if s[0] not in [defaults.ENDED]] + ), + ) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) + + response = self.client.post( + f"/api/videos/{video.id}/initiate-transcript/", + HTTP_AUTHORIZATION=f"Bearer {jwt_token}", + ) + + self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST) + def test_api_video_initiate_transcript_token_user(self): """A token user associated to a video should be able to initiate a transcript.""" video = factories.VideoFactory( @@ -86,6 +104,48 @@ def test_api_video_initiate_transcript_token_user(self): self.assertEqual(timed_text_track.mode, models.TimedTextTrack.TRANSCRIPT) self.assertEqual(timed_text_track.upload_state, defaults.PROCESSING) + def test_api_video_initiate_transcript_token_user_live_state_ended(self): + """ + A token user associated to a video with live_state ended should be able to initiate + a transcript. + """ + video = factories.VideoFactory( + pk="a2f27fde-973a-4e89-8dca-cc59e01d255c", + live_type=defaults.JITSI, + live_state=defaults.ENDED, + upload_state=defaults.READY, + uploaded_on=datetime(2018, 8, 8, tzinfo=baseTimezone.utc), + transcode_pipeline=defaults.PEERTUBE_PIPELINE, + resolutions=[720, 1080], + playlist__title="foo bar", + ) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) + + with self.settings(LANGUAGES=(("en", "English"),)), mock.patch( + "marsha.core.api.video.launch_video_transcript.delay" + ) as mock_launch_video_transcript, mock.patch.object( + channel_layers_utils, "dispatch_timed_text_track" + ) as mock_dispatch_timed_text_track, mock.patch.object( + channel_layers_utils, "dispatch_video" + ) as mock_dispatch_video: + response = self.client.post( + f"/api/videos/{video.id}/initiate-transcript/", + HTTP_AUTHORIZATION=f"Bearer {jwt_token}", + ) + + self.assertEqual(response.status_code, HTTPStatus.OK) + mock_launch_video_transcript.assert_called_once_with( + video_pk=video.pk, stamp="1533686400", domain="http://testserver" + ) + + timed_text_track = video.timedtexttracks.get() + mock_dispatch_timed_text_track.assert_called_once_with(timed_text_track) + mock_dispatch_video.assert_called_once_with(video) + + self.assertEqual(timed_text_track.language, "en") + self.assertEqual(timed_text_track.mode, models.TimedTextTrack.TRANSCRIPT) + self.assertEqual(timed_text_track.upload_state, defaults.PROCESSING) + def test_api_video_initiate_transcript_staff_or_user(self): """Users authenticated via a session should not be able to retrieve a transcript policy.""" for user in [factories.UserFactory(), factories.UserFactory(is_staff=True)]: