Download transcript on video upload page - EDUCATOR-1853

This commit is contained in:
Qubad786
2017-12-18 19:55:41 +05:00
committed by Mushtaq Ali
parent e601767329
commit c760c6a01b
9 changed files with 186 additions and 8 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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;

View File

@@ -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>

View File

@@ -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),

View File

@@ -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