Download transcript on video upload page - EDUCATOR-1853
This commit is contained in:
@@ -169,3 +169,111 @@ class TranscriptCredentialsValidationTest(TestCase):
|
||||
# Assert the results.
|
||||
self.assertEqual(error_message, expected_error_message)
|
||||
self.assertDictEqual(validated_credentials, expected_validated_credentials)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@patch(
|
||||
'openedx.core.djangoapps.video_config.models.VideoTranscriptEnabledFlag.feature_enabled',
|
||||
Mock(return_value=True)
|
||||
)
|
||||
class TranscriptDownloadTest(CourseTestCase):
|
||||
"""
|
||||
Tests for transcript download handler.
|
||||
"""
|
||||
VIEW_NAME = 'transcript_download_handler'
|
||||
|
||||
def get_url_for_course_key(self, course_id):
|
||||
return reverse_course_url(self.VIEW_NAME, course_id)
|
||||
|
||||
def test_302_with_anonymous_user(self):
|
||||
"""
|
||||
Verify that redirection happens in case of unauthorized request.
|
||||
"""
|
||||
self.client.logout()
|
||||
transcript_download_url = self.get_url_for_course_key(self.course.id)
|
||||
response = self.client.get(transcript_download_url, content_type='application/json')
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_405_with_not_allowed_request_method(self):
|
||||
"""
|
||||
Verify that 405 is returned in case of not-allowed request methods.
|
||||
Allowed request methods include GET.
|
||||
"""
|
||||
transcript_download_url = self.get_url_for_course_key(self.course.id)
|
||||
response = self.client.post(transcript_download_url, content_type='application/json')
|
||||
self.assertEqual(response.status_code, 405)
|
||||
|
||||
def test_404_with_feature_disabled(self):
|
||||
"""
|
||||
Verify that 404 is returned if the corresponding feature is disabled.
|
||||
"""
|
||||
transcript_download_url = self.get_url_for_course_key(self.course.id)
|
||||
with patch('openedx.core.djangoapps.video_config.models.VideoTranscriptEnabledFlag.feature_enabled') as feature:
|
||||
feature.return_value = False
|
||||
response = self.client.get(transcript_download_url, content_type='application/json')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
@patch('contentstore.views.transcript_settings.get_video_transcript_data')
|
||||
def test_transcript_download_handler(self, mock_get_video_transcript_data):
|
||||
"""
|
||||
Tests that transcript download handler works as expected.
|
||||
"""
|
||||
transcript_download_url = self.get_url_for_course_key(self.course.id)
|
||||
mock_get_video_transcript_data.return_value = {
|
||||
'content': json.dumps({
|
||||
"start": [10],
|
||||
"end": [100],
|
||||
"text": ["Hi, welcome to Edx."],
|
||||
}),
|
||||
'file_name': 'edx.sjson'
|
||||
}
|
||||
|
||||
# Make request to transcript download handler
|
||||
response = self.client.get(
|
||||
transcript_download_url,
|
||||
data={
|
||||
'edx_video_id': '123',
|
||||
'language_code': 'en'
|
||||
},
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
# Expected response
|
||||
expected_content = u'0\n00:00:00,010 --> 00:00:00,100\nHi, welcome to Edx.\n\n'
|
||||
expected_headers = {
|
||||
'Content-Disposition': 'attachment; filename="edx.srt"',
|
||||
'Content-Language': u'en',
|
||||
'Content-Type': 'application/x-subrip; charset=utf-8'
|
||||
}
|
||||
|
||||
# Assert the actual response
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, expected_content)
|
||||
for attribute, value in expected_headers.iteritems():
|
||||
self.assertEqual(response.get(attribute), value)
|
||||
|
||||
@ddt.data(
|
||||
(
|
||||
{},
|
||||
u'Following parameters are required: edx_video_id, language_code.'
|
||||
),
|
||||
(
|
||||
{'edx_video_id': '123'},
|
||||
u'Following parameters are required: language_code.'
|
||||
),
|
||||
(
|
||||
{'language_code': 'en'},
|
||||
u'Following parameters are required: edx_video_id.'
|
||||
),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_transcript_download_handler_missing_attrs(self, request_payload, expected_error_message):
|
||||
"""
|
||||
Tests that transcript download handler with missing attributes.
|
||||
"""
|
||||
# Make request to transcript download handler
|
||||
transcript_download_url = self.get_url_for_course_key(self.course.id)
|
||||
response = self.client.get(transcript_download_url, data=request_payload)
|
||||
# Assert the response
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(json.loads(response.content)['error'], expected_error_message)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
"""
|
||||
Views related to the transcript preferences feature
|
||||
"""
|
||||
import os
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponseNotFound
|
||||
from django.http import HttpResponseNotFound, HttpResponse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.views.decorators.http import require_POST, require_GET
|
||||
from edxval.api import (
|
||||
get_3rd_party_transcription_plans,
|
||||
get_video_transcript_data,
|
||||
update_transcript_credentials_state_for_org,
|
||||
)
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
@@ -16,8 +19,9 @@ from openedx.core.djangoapps.video_pipeline.api import update_3rd_party_transcri
|
||||
from util.json_request import JsonResponse, expect_json
|
||||
|
||||
from contentstore.views.videos import TranscriptProvider
|
||||
from xmodule.video_module.transcripts_utils import Transcript
|
||||
|
||||
__all__ = ['transcript_credentials_handler']
|
||||
__all__ = ['transcript_credentials_handler', 'transcript_download_handler']
|
||||
|
||||
|
||||
class TranscriptionProviderErrorType:
|
||||
@@ -108,3 +112,46 @@ def transcript_credentials_handler(request, course_key_string):
|
||||
response = JsonResponse({'error': error_message}, status=400)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@login_required
|
||||
@require_GET
|
||||
def transcript_download_handler(request, course_key_string):
|
||||
"""
|
||||
JSON view handler to download a transcript.
|
||||
|
||||
Arguments:
|
||||
request: WSGI request object
|
||||
course_key_string: course key
|
||||
|
||||
Returns:
|
||||
- A 200 response with SRT transcript file attached.
|
||||
- A 400 if there is a validation error.
|
||||
- A 404 if there is no such transcript or feature flag is disabled.
|
||||
"""
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
if not VideoTranscriptEnabledFlag.feature_enabled(course_key):
|
||||
return HttpResponseNotFound()
|
||||
|
||||
missing = [attr for attr in ['edx_video_id', 'language_code'] if attr not in request.GET]
|
||||
if missing:
|
||||
return JsonResponse(
|
||||
{'error': _(u'Following parameters are required: {missing}.').format(missing=', '.join(missing))},
|
||||
status=400
|
||||
)
|
||||
|
||||
edx_video_id = request.GET['edx_video_id']
|
||||
language_code = request.GET['language_code']
|
||||
transcript = get_video_transcript_data(video_ids=[edx_video_id], language_code=language_code)
|
||||
if transcript:
|
||||
name_and_extension = os.path.splitext(transcript['file_name'])
|
||||
basename, file_format = name_and_extension[0], name_and_extension[1][1:]
|
||||
transcript_filename = '{base_name}.srt'.format(base_name=basename.encode('utf8'))
|
||||
transcript_content = Transcript.convert(transcript['content'], input_format=file_format, output_format='srt')
|
||||
# Construct an HTTP response
|
||||
response = HttpResponse(transcript_content, content_type=Transcript.mime_types['srt'])
|
||||
response['Content-Disposition'] = 'attachment; filename="{filename}"'.format(filename=transcript_filename)
|
||||
else:
|
||||
response = HttpResponseNotFound()
|
||||
|
||||
return response
|
||||
|
||||
@@ -643,6 +643,10 @@ def videos_index_html(course):
|
||||
'transcript_credentials_handler',
|
||||
unicode(course.id)
|
||||
),
|
||||
'transcript_download_handler_url': reverse_course_url(
|
||||
'transcript_download_handler',
|
||||
unicode(course.id)
|
||||
),
|
||||
'transcription_plans': get_3rd_party_transcription_plans(),
|
||||
'trancript_download_file_format': TRANSCRIPT_DOWNLOAD_FILE_FORMAT
|
||||
}
|
||||
|
||||
@@ -22,9 +22,11 @@ define(
|
||||
ur: 'Urdu'
|
||||
},
|
||||
TRANSCRIPT_DOWNLOAD_FILE_FORMAT = 'srt',
|
||||
TRANSCRIPT_DOWNLOAD_URL = 'abc.com/transcript_download/course_id',
|
||||
videoSupportedFileFormats = ['.mov', '.mp4'],
|
||||
videoTranscriptSettings = {
|
||||
trancript_download_file_format: TRANSCRIPT_DOWNLOAD_FILE_FORMAT
|
||||
trancript_download_file_format: TRANSCRIPT_DOWNLOAD_FILE_FORMAT,
|
||||
transcript_download_handler_url: TRANSCRIPT_DOWNLOAD_URL
|
||||
},
|
||||
videoListView;
|
||||
|
||||
@@ -33,7 +35,10 @@ define(
|
||||
uploadTranscriptActionEl = $transcriptActionsEl.find('.upload-transcript-button');
|
||||
|
||||
expect(downloadTranscriptActionEl.html().trim(), 'Download');
|
||||
expect(downloadTranscriptActionEl.attr('href'), '#');
|
||||
expect(
|
||||
downloadTranscriptActionEl.attr('href'),
|
||||
TRANSCRIPT_DOWNLOAD_URL + '?edx_video_id=' + edxVideoID + '&language_code=' + transcriptLanguage
|
||||
);
|
||||
|
||||
expect(uploadTranscriptActionEl.html().trim(), 'Upload');
|
||||
expect(uploadTranscriptActionEl.data('edx-video-id'), edxVideoID);
|
||||
|
||||
@@ -18,6 +18,7 @@ define(
|
||||
defaultVideoImageURL: options.defaultVideoImageURL,
|
||||
videoHandlerUrl: options.videoHandlerUrl,
|
||||
videoImageSettings: options.videoImageSettings,
|
||||
videoTranscriptSettings: options.videoTranscriptSettings,
|
||||
model: model,
|
||||
transcriptAvailableLanguages: options.transcriptAvailableLanguages,
|
||||
videoSupportedFileFormats: options.videoSupportedFileFormats,
|
||||
|
||||
@@ -85,7 +85,8 @@ define(
|
||||
transcriptAvailableLanguages: this.sortByValue(this.transcriptAvailableLanguages),
|
||||
edxVideoID: this.edxVideoID,
|
||||
transcriptClientTitle: this.getTranscriptClientTitle(),
|
||||
transcriptDownloadFileFormat: this.videoTranscriptSettings.trancript_download_file_format
|
||||
transcriptDownloadFileFormat: this.videoTranscriptSettings.trancript_download_file_format,
|
||||
transcriptDownloadHandlerUrl: this.videoTranscriptSettings.transcript_download_handler_url
|
||||
})
|
||||
);
|
||||
return this;
|
||||
|
||||
@@ -22,7 +22,17 @@
|
||||
<% }) %>
|
||||
</select>
|
||||
<div class='transcript-actions'>
|
||||
<a class="button-link download-transcript-button" href="#" data-edx-video-id="<%- edxVideoID %>" data-language-code="<%- transcriptLanguageCode %>">
|
||||
<a
|
||||
class="button-link download-transcript-button"
|
||||
href="<%- StringUtils.interpolate(
|
||||
'{transcriptDownloadHandlerUrl}?edx_video_id={edxVideoID}&language_code={transcriptLanguageCode}',
|
||||
{
|
||||
transcriptDownloadHandlerUrl: transcriptDownloadHandlerUrl,
|
||||
edxVideoID: edxVideoID,
|
||||
transcriptLanguageCode: transcriptLanguageCode
|
||||
}
|
||||
) %>"
|
||||
>
|
||||
<%- gettext('Download') %>
|
||||
</a>
|
||||
<span class='transcript-actions-separator'> | </span>
|
||||
|
||||
@@ -142,6 +142,8 @@ urlpatterns = [
|
||||
contentstore.views.transcript_preferences_handler, name='transcript_preferences_handler'),
|
||||
url(r'^transcript_credentials/{}$'.format(settings.COURSE_KEY_PATTERN),
|
||||
contentstore.views.transcript_credentials_handler, name='transcript_credentials_handler'),
|
||||
url(r'^transcript_download/{}$'.format(settings.COURSE_KEY_PATTERN),
|
||||
contentstore.views.transcript_download_handler, name='transcript_download_handler'),
|
||||
url(r'^video_encodings_download/{}$'.format(settings.COURSE_KEY_PATTERN),
|
||||
contentstore.views.video_encodings_download, name='video_encodings_download'),
|
||||
url(r'^group_configurations/{}$'.format(settings.COURSE_KEY_PATTERN),
|
||||
|
||||
@@ -105,4 +105,4 @@ xblock-review==1.1.2
|
||||
|
||||
git+https://github.com/mitodl/edx-sga.git@d019b8a050c056db535e3ff13c93096145a932de#egg=edx-sga==0.7.1
|
||||
git+https://github.com/open-craft/xblock-poll@7ba819b968fe8faddb78bb22e1fe7637005eb414#egg=xblock-poll==1.2.7
|
||||
git+https://github.com/edx-solutions/xblock-drag-and-drop-v2@2.1.5#egg=xblock-drag-and-drop-v2==2.1.5
|
||||
git+https://github.com/edx-solutions/xblock-drag-and-drop-v2@2.1.5#egg=xblock-drag-and-drop-v2==2.1.5
|
||||
Reference in New Issue
Block a user