Merge pull request #17122 from edx/mrehan/delete-transcripts
Delete transcript
This commit is contained in:
@@ -5,11 +5,13 @@ from io import BytesIO
|
||||
from mock import Mock, patch, ANY
|
||||
|
||||
from django.test.testcases import TestCase
|
||||
from edxval import api
|
||||
|
||||
from contentstore.tests.utils import CourseTestCase
|
||||
from contentstore.utils import reverse_course_url
|
||||
from contentstore.views.transcript_settings import TranscriptionProviderErrorType, validate_transcript_credentials
|
||||
from openedx.core.djangoapps.profile_images.tests.helpers import make_image_file
|
||||
from student.roles import CourseStaffRole
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -468,3 +470,112 @@ class TranscriptUploadTest(CourseTestCase):
|
||||
json.loads(response.content)['error'],
|
||||
u'There is a problem with this transcript file. Try to upload a different file.'
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@patch(
|
||||
'openedx.core.djangoapps.video_config.models.VideoTranscriptEnabledFlag.feature_enabled',
|
||||
Mock(return_value=True)
|
||||
)
|
||||
class TranscriptUploadTest(CourseTestCase):
|
||||
"""
|
||||
Tests for transcript deletion handler.
|
||||
"""
|
||||
VIEW_NAME = 'transcript_delete_handler'
|
||||
|
||||
def get_url_for_course_key(self, course_id, **kwargs):
|
||||
return reverse_course_url(self.VIEW_NAME, course_id, kwargs)
|
||||
|
||||
def test_302_with_anonymous_user(self):
|
||||
"""
|
||||
Verify that redirection happens in case of unauthorized request.
|
||||
"""
|
||||
self.client.logout()
|
||||
transcript_delete_url = self.get_url_for_course_key(self.course.id, edx_video_id='test_id', language_code='en')
|
||||
response = self.client.delete(transcript_delete_url)
|
||||
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 DELETE.
|
||||
"""
|
||||
transcript_delete_url = self.get_url_for_course_key(self.course.id, edx_video_id='test_id', language_code='en')
|
||||
response = self.client.post(transcript_delete_url)
|
||||
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_delete_url = self.get_url_for_course_key(self.course.id, edx_video_id='test_id', language_code='en')
|
||||
with patch('openedx.core.djangoapps.video_config.models.VideoTranscriptEnabledFlag.feature_enabled') as feature:
|
||||
feature.return_value = False
|
||||
response = self.client.delete(transcript_delete_url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_404_with_non_staff_user(self):
|
||||
"""
|
||||
Verify that 404 is returned if the user doesn't have studio write access.
|
||||
"""
|
||||
# Making sure that user is not a staff / course's staff.
|
||||
self.user.is_staff = False
|
||||
self.user.save()
|
||||
|
||||
# Assert the user's role
|
||||
self.assertFalse(self.user.is_staff)
|
||||
self.assertFalse(CourseStaffRole(self.course.id).has_user(self.user))
|
||||
|
||||
# Now, Make request to deletion handler
|
||||
transcript_delete_url = self.get_url_for_course_key(self.course.id, edx_video_id='test_id', language_code='en')
|
||||
response = self.client.delete(transcript_delete_url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
@ddt.data(
|
||||
{
|
||||
'is_staff': True,
|
||||
'is_course_staff': True
|
||||
},
|
||||
{
|
||||
'is_staff': False,
|
||||
'is_course_staff': True
|
||||
},
|
||||
{
|
||||
'is_staff': True,
|
||||
'is_course_staff': False
|
||||
},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_transcript_delete_handler(self, is_staff, is_course_staff):
|
||||
"""
|
||||
Tests that transcript delete handler works as expected with combinations of staff and course's staff.
|
||||
"""
|
||||
# Setup user's roles
|
||||
self.user.is_staff = is_staff
|
||||
self.user.save()
|
||||
course_staff_role = CourseStaffRole(self.course.id)
|
||||
if is_course_staff:
|
||||
course_staff_role.add_users(self.user)
|
||||
else:
|
||||
course_staff_role.remove_users(self.user)
|
||||
|
||||
# Assert the user role
|
||||
self.assertEqual(self.user.is_staff, is_staff)
|
||||
self.assertEqual(CourseStaffRole(self.course.id).has_user(self.user), is_course_staff)
|
||||
|
||||
video_id, language_code = u'1234', u'en'
|
||||
# Create a real transcript in VAL.
|
||||
api.create_or_update_video_transcript(
|
||||
video_id=video_id,
|
||||
language_code=language_code,
|
||||
metadata={'file_format': 'srt'}
|
||||
)
|
||||
|
||||
# Make request to transcript deletion handler
|
||||
response = self.client.delete(self.get_url_for_course_key(
|
||||
self.course.id,
|
||||
edx_video_id=video_id,
|
||||
language_code=language_code
|
||||
))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertFalse(api.get_video_transcript_data([video_id], language_code=language_code))
|
||||
|
||||
@@ -9,9 +9,10 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.core.files.base import ContentFile
|
||||
from django.http import HttpResponseNotFound, HttpResponse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.decorators.http import require_POST, require_GET
|
||||
from django.views.decorators.http import require_http_methods, require_POST, require_GET
|
||||
from edxval.api import (
|
||||
create_or_update_video_transcript,
|
||||
delete_video_transcript,
|
||||
get_available_transcript_languages,
|
||||
get_3rd_party_transcription_plans,
|
||||
get_video_transcript_data,
|
||||
@@ -21,12 +22,18 @@ from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.video_config.models import VideoTranscriptEnabledFlag
|
||||
from openedx.core.djangoapps.video_pipeline.api import update_3rd_party_transcription_service_credentials
|
||||
from student.auth import has_studio_write_access
|
||||
from util.json_request import JsonResponse, expect_json
|
||||
|
||||
from contentstore.views.videos import TranscriptProvider
|
||||
from xmodule.video_module.transcripts_utils import Transcript, TranscriptsGenerationException
|
||||
|
||||
__all__ = ['transcript_credentials_handler', 'transcript_download_handler', 'transcript_upload_handler']
|
||||
__all__ = [
|
||||
'transcript_credentials_handler',
|
||||
'transcript_download_handler',
|
||||
'transcript_upload_handler',
|
||||
'transcript_delete_handler'
|
||||
]
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -254,3 +261,31 @@ def transcript_upload_handler(request, course_key_string):
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@login_required
|
||||
@require_http_methods(["DELETE"])
|
||||
def transcript_delete_handler(request, course_key_string, edx_video_id, language_code):
|
||||
"""
|
||||
View to delete a transcript file.
|
||||
|
||||
Arguments:
|
||||
request: A WSGI request object
|
||||
course_key_string: Course key identifying a course.
|
||||
edx_video_id: edX video identifier whose transcript need to be deleted.
|
||||
language_code: transcript's language code.
|
||||
|
||||
Returns
|
||||
- A 404 if the corresponding feature flag is disabled or user does not have required permisions
|
||||
- A 200 if transcript is deleted without any error(s)
|
||||
"""
|
||||
# Check whether the feature is available for this course.
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
video_transcripts_enabled = VideoTranscriptEnabledFlag.feature_enabled(course_key)
|
||||
# User needs to have studio write access for this course.
|
||||
if not video_transcripts_enabled or not has_studio_write_access(request.user, course_key):
|
||||
return HttpResponseNotFound()
|
||||
|
||||
delete_video_transcript(video_id=edx_video_id, language_code=language_code)
|
||||
|
||||
return JsonResponse(status=200)
|
||||
|
||||
@@ -597,7 +597,7 @@ def get_all_transcript_languages():
|
||||
all_languages_dict = dict(settings.ALL_LANGUAGES, **third_party_transcription_languages)
|
||||
# Return combined system settings and 3rd party transcript languages.
|
||||
all_languages = []
|
||||
for key, value in sorted(all_languages_dict.iteritems(), key=lambda (k, v): (v, k)):
|
||||
for key, value in sorted(all_languages_dict.iteritems(), key=lambda (k, v): v):
|
||||
all_languages.append({
|
||||
'language_code': key,
|
||||
'language_text': value
|
||||
@@ -653,6 +653,10 @@ def videos_index_html(course):
|
||||
'transcript_upload_handler',
|
||||
unicode(course.id)
|
||||
),
|
||||
'transcript_delete_handler_url': reverse_course_url(
|
||||
'transcript_delete_handler',
|
||||
unicode(course.id)
|
||||
),
|
||||
'transcription_plans': get_3rd_party_transcription_plans(),
|
||||
'trancript_download_file_format': Transcript.SRT
|
||||
}
|
||||
|
||||
@@ -34,11 +34,13 @@ define(
|
||||
TRANSCRIPT_DOWNLOAD_FILE_FORMAT = 'srt',
|
||||
TRANSCRIPT_DOWNLOAD_URL = 'abc.com/transcript_download/course_id',
|
||||
TRANSCRIPT_UPLOAD_URL = 'abc.com/transcript_upload/course_id',
|
||||
TRANSCRIPT_DELETE_URL = 'abc.com/transcript_delete/course_id',
|
||||
videoSupportedFileFormats = ['.mov', '.mp4'],
|
||||
videoTranscriptSettings = {
|
||||
trancript_download_file_format: TRANSCRIPT_DOWNLOAD_FILE_FORMAT,
|
||||
transcript_download_handler_url: TRANSCRIPT_DOWNLOAD_URL,
|
||||
transcript_upload_handler_url: TRANSCRIPT_UPLOAD_URL
|
||||
transcript_upload_handler_url: TRANSCRIPT_UPLOAD_URL,
|
||||
transcript_delete_handler_url: TRANSCRIPT_DELETE_URL
|
||||
},
|
||||
videoListView;
|
||||
|
||||
@@ -119,6 +121,7 @@ define(
|
||||
beforeEach(function() {
|
||||
setFixtures(
|
||||
'<div id="page-prompt"></div>' +
|
||||
'<div id="page-notification"></div>' +
|
||||
'<section class="wrapper-assets"></section>'
|
||||
);
|
||||
TemplateHelpers.installTemplate('previous-video-upload-list');
|
||||
@@ -127,7 +130,7 @@ define(
|
||||
|
||||
it('renders as expected', function() {
|
||||
// Verify transcript container is present.
|
||||
expect(videoListView.$el.find('.show-video-transcripts-container')).toExist();
|
||||
expect(videoListView.$el.find('.video-transcripts-header')).toExist();
|
||||
// Veirfy transcript column header is present.
|
||||
expect(videoListView.$el.find('.js-table-head .video-head-col.transcripts-col')).toExist();
|
||||
// Verify transcript data column is present.
|
||||
@@ -139,7 +142,7 @@ define(
|
||||
it('does not render transcripts view if feature is disabled', function() {
|
||||
renderView(transcripts, false);
|
||||
// Verify transcript container is not present.
|
||||
expect(videoListView.$el.find('.show-video-transcripts-container')).not.toExist();
|
||||
expect(videoListView.$el.find('.video-transcripts-header')).not.toExist();
|
||||
// Veirfy transcript column header is not present.
|
||||
expect(videoListView.$el.find('.js-table-head .video-head-col.transcripts-col')).not.toExist();
|
||||
// Verify transcript data column is not present.
|
||||
@@ -150,7 +153,7 @@ define(
|
||||
|
||||
it('does not show list of transcripts initially', function() {
|
||||
expect(
|
||||
videoTranscriptsView.$el.find('.show-video-transcripts-wrapper').hasClass('hidden')
|
||||
videoTranscriptsView.$el.find('.video-transcripts-wrapper').hasClass('hidden')
|
||||
).toEqual(true);
|
||||
expect(videoTranscriptsView.$el.find('.toggle-show-transcripts-button-text').html().trim()).toEqual(
|
||||
'Show transcripts (' + transcripts.length + ')'
|
||||
@@ -160,7 +163,7 @@ define(
|
||||
it('shows list of transcripts when clicked on show transcript button', function() {
|
||||
// Verify transcript container is hidden
|
||||
expect(
|
||||
videoTranscriptsView.$el.find('.show-video-transcripts-wrapper').hasClass('hidden')
|
||||
videoTranscriptsView.$el.find('.video-transcripts-wrapper').hasClass('hidden')
|
||||
).toEqual(true);
|
||||
|
||||
// Verify initial button text
|
||||
@@ -171,7 +174,7 @@ define(
|
||||
|
||||
// Verify transcript container is not hidden
|
||||
expect(
|
||||
videoTranscriptsView.$el.find('.show-video-transcripts-wrapper').hasClass('hidden')
|
||||
videoTranscriptsView.$el.find('.video-transcripts-wrapper').hasClass('hidden')
|
||||
).toEqual(false);
|
||||
|
||||
// Verify button text is changed.
|
||||
@@ -191,7 +194,7 @@ define(
|
||||
|
||||
// Verify transcript container is not hidden
|
||||
expect(
|
||||
videoTranscriptsView.$el.find('.show-video-transcripts-wrapper').hasClass('hidden')
|
||||
videoTranscriptsView.$el.find('.video-transcripts-wrapper').hasClass('hidden')
|
||||
).toEqual(false);
|
||||
|
||||
videoTranscriptsView.$el.find('.toggle-show-transcripts-button').click();
|
||||
@@ -203,7 +206,7 @@ define(
|
||||
|
||||
// Verify transcript container is hidden
|
||||
expect(
|
||||
videoTranscriptsView.$el.find('.show-video-transcripts-wrapper').hasClass('hidden')
|
||||
videoTranscriptsView.$el.find('.video-transcripts-wrapper').hasClass('hidden')
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -221,12 +224,12 @@ define(
|
||||
var $transcriptEl;
|
||||
// Show transcripts
|
||||
videoTranscriptsView.$el.find('.toggle-show-transcripts-button').click();
|
||||
expect(videoTranscriptsView.$el.find('.show-video-transcript-content').length).toEqual(
|
||||
expect(videoTranscriptsView.$el.find('.video-transcript-content').length).toEqual(
|
||||
transcripts.length
|
||||
);
|
||||
|
||||
_.each(transcripts, function(languageCode) {
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.show-video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
// Verify correct transcript title is set.
|
||||
expect($transcriptEl.find('.transcript-title').html()).toEqual(
|
||||
'Video client title n_' + languageCode + '.' + TRANSCRIPT_DOWNLOAD_FILE_FORMAT
|
||||
@@ -240,7 +243,7 @@ define(
|
||||
var languageCode = 'en',
|
||||
newLanguageCode = 'ar',
|
||||
requests = AjaxHelpers.requests(this),
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.show-video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
// Verify correct transcript title is set.
|
||||
expect($transcriptEl.find('.transcript-title').html()).toEqual(
|
||||
@@ -255,7 +258,7 @@ define(
|
||||
// Add transcript to upload queue and send POST request to upload transcript.
|
||||
$transcriptEl.find('.upload-transcript-input').fileupload('add', {files: [createFakeTranscriptFile()]});
|
||||
|
||||
// Verify if POST request received for image upload
|
||||
// Verify if POST request received for transcript upload
|
||||
AjaxHelpers.expectRequest(
|
||||
requests,
|
||||
'POST',
|
||||
@@ -276,11 +279,97 @@ define(
|
||||
verifyTranscriptStateInfo($transcriptEl, newLanguageCode);
|
||||
});
|
||||
|
||||
it('can delete transcript', function() {
|
||||
var languageCode = 'en',
|
||||
requests = AjaxHelpers.requests(this),
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
// Verify correct transcript title is set.
|
||||
expect($transcriptEl.find('.transcript-title').html()).toEqual(
|
||||
'Video client title n_' + languageCode + '.' + TRANSCRIPT_DOWNLOAD_FILE_FORMAT
|
||||
);
|
||||
|
||||
$transcriptEl.find('.delete-transcript-button').click();
|
||||
|
||||
// Click remove button on prompt.
|
||||
$('#page-prompt .action-primary').click();
|
||||
|
||||
// Verify if DELETE request received for transcript delete
|
||||
AjaxHelpers.expectRequest(
|
||||
requests,
|
||||
'DELETE',
|
||||
TRANSCRIPT_DELETE_URL + '/' + edxVideoID + '/' + languageCode
|
||||
);
|
||||
|
||||
// Send successful delete response
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
|
||||
// Verify English transcript is not present.
|
||||
expect(videoTranscriptsView.$el.find(
|
||||
'.video-transcript-content[data-language-code="' + languageCode + '"]'
|
||||
)).not.toExist();
|
||||
|
||||
// Verify transcripts view is rendered with transcript deleted for English.
|
||||
expect(videoTranscriptsView.$el.find('.toggle-show-transcripts-button-text').html().trim()).toEqual(
|
||||
'Show transcripts (2)'
|
||||
);
|
||||
});
|
||||
|
||||
it('should show error message when deleting a transcript in case of server error', function() {
|
||||
var languageCode = 'en',
|
||||
requests = AjaxHelpers.requests(this),
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
// Verify correct transcript title is set.
|
||||
expect($transcriptEl.find('.transcript-title').html()).toEqual(
|
||||
'Video client title n_' + languageCode + '.' + TRANSCRIPT_DOWNLOAD_FILE_FORMAT
|
||||
);
|
||||
|
||||
$transcriptEl.find('.delete-transcript-button').click();
|
||||
|
||||
// Verify prompt title and description.
|
||||
|
||||
expect($('#page-prompt #prompt-warning-title').html().trim()).toEqual(
|
||||
'Are you sure you want to remove this transcript?'
|
||||
);
|
||||
|
||||
expect($('#page-prompt #prompt-warning-description').html().trim()).toEqual(
|
||||
'If you remove this transcript, the transcript will not be available for any components that use this video.' // eslint-disable-line max-len
|
||||
);
|
||||
|
||||
// Click remove button on prompt.
|
||||
$('#page-prompt .action-primary').click();
|
||||
|
||||
// Verify if DELETE request received for transcript delete.
|
||||
AjaxHelpers.expectRequest(
|
||||
requests,
|
||||
'DELETE',
|
||||
TRANSCRIPT_DELETE_URL + '/' + edxVideoID + '/' + languageCode
|
||||
);
|
||||
|
||||
AjaxHelpers.respondWithError(requests, 500);
|
||||
|
||||
// Verify prompt message is shown.
|
||||
expect($('#page-notification #notification-error-title').html()).toEqual(
|
||||
"Studio's having trouble saving your work"
|
||||
);
|
||||
|
||||
// Verify English transcript container is not removed.
|
||||
expect(videoTranscriptsView.$el.find(
|
||||
'.video-transcript-content[data-language-code="' + languageCode + '"]'
|
||||
)).toExist();
|
||||
|
||||
// Verify transcripts count is correct.
|
||||
expect(videoTranscriptsView.$el.find('.toggle-show-transcripts-button-text').html().trim()).toEqual(
|
||||
'Show transcripts (3)'
|
||||
);
|
||||
});
|
||||
|
||||
it('shows error state correctly', function() {
|
||||
var languageCode = 'en',
|
||||
requests = AjaxHelpers.requests(this),
|
||||
errorMessage = 'Transcript failed error message',
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.show-video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
$transcriptEl.find('.upload-transcript-button').click();
|
||||
|
||||
@@ -306,7 +395,7 @@ define(
|
||||
it('should show error message in case of server error', function() {
|
||||
var languageCode = 'en',
|
||||
requests = AjaxHelpers.requests(this),
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.show-video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
$transcriptEl.find('.upload-transcript-button').click();
|
||||
|
||||
@@ -332,7 +421,7 @@ define(
|
||||
var languageCode = 'en',
|
||||
transcriptFileName = 'unsupported-transcript-file-format.txt',
|
||||
errorMessage = 'This file type is not supported. Supported file type is ' + TRANSCRIPT_DOWNLOAD_FILE_FORMAT + '.', // eslint-disable-line max-len
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.show-video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
$transcriptEl = videoTranscriptsView.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
$transcriptEl.find('.upload-transcript-button').click();
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
define(
|
||||
['underscore', 'gettext', 'js/views/baseview', 'common/js/components/views/feedback_prompt',
|
||||
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/string-utils',
|
||||
'text!templates/video-transcripts.underscore', 'text!templates/video-transcript-upload-status.underscore'],
|
||||
function(_, gettext, BaseView, PromptView, HtmlUtils, StringUtils, videoTranscriptsTemplate,
|
||||
'common/js/components/utils/view_utils', 'text!templates/video-transcripts.underscore',
|
||||
'text!templates/video-transcript-upload-status.underscore'],
|
||||
function(_, gettext, BaseView, PromptView, HtmlUtils, StringUtils, ViewUtils, videoTranscriptsTemplate,
|
||||
videoTranscriptUploadStatusTemplate) {
|
||||
'use strict';
|
||||
|
||||
@@ -12,10 +13,12 @@ define(
|
||||
events: {
|
||||
'click .toggle-show-transcripts-button': 'toggleShowTranscripts',
|
||||
'click .upload-transcript-button': 'chooseFile',
|
||||
'click .delete-transcript-button': 'deleteTranscript',
|
||||
'click .more-details-action': 'showUploadFailureMessage'
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.isCollapsed = true;
|
||||
this.transcripts = options.transcripts;
|
||||
this.edxVideoID = options.edxVideoID;
|
||||
this.clientVideoID = options.clientVideoID;
|
||||
@@ -85,33 +88,71 @@ define(
|
||||
);
|
||||
},
|
||||
|
||||
/*
|
||||
Returns transcript delete handler url.
|
||||
*/
|
||||
getTranscriptDeleteUrl: function(edxVideoID, transcriptLanguageCode, transcriptDeleteHandlerUrl) {
|
||||
return StringUtils.interpolate(
|
||||
'{transcriptDeleteHandlerUrl}/{edxVideoID}/{transcriptLanguageCode}',
|
||||
{
|
||||
transcriptDeleteHandlerUrl: transcriptDeleteHandlerUrl,
|
||||
edxVideoID: edxVideoID,
|
||||
transcriptLanguageCode: transcriptLanguageCode
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/*
|
||||
Toggles Show/Hide transcript button and transcripts container.
|
||||
*/
|
||||
toggleShowTranscripts: function() {
|
||||
var $transcriptsWrapperEl = this.$el.find('.show-video-transcripts-wrapper');
|
||||
var $transcriptsWrapperEl = this.$el.find('.video-transcripts-wrapper');
|
||||
|
||||
// Toggle show transcript wrapper.
|
||||
$transcriptsWrapperEl.toggleClass('hidden');
|
||||
if ($transcriptsWrapperEl.hasClass('hidden')) {
|
||||
this.showTranscripts();
|
||||
this.isCollapsed = false;
|
||||
} else {
|
||||
this.hideTranscripts();
|
||||
this.isCollapsed = true;
|
||||
}
|
||||
},
|
||||
|
||||
// Toggle button text.
|
||||
showTranscripts: function() {
|
||||
// Show transcript wrapper
|
||||
this.$el.find('.video-transcripts-wrapper').removeClass('hidden');
|
||||
|
||||
// Update button text.
|
||||
HtmlUtils.setHtml(
|
||||
this.$el.find('.toggle-show-transcripts-button-text'),
|
||||
StringUtils.interpolate(
|
||||
gettext('{toggleShowTranscriptText} transcripts ({totalTranscripts})'),
|
||||
gettext('Hide transcripts ({transcriptCount})'),
|
||||
{
|
||||
toggleShowTranscriptText: $transcriptsWrapperEl.hasClass('hidden') ? gettext('Show') : gettext('Hide'), // eslint-disable-line max-len
|
||||
totalTranscripts: this.transcripts.length
|
||||
transcriptCount: this.transcripts.length
|
||||
}
|
||||
)
|
||||
);
|
||||
this.$el.find('.toggle-show-transcripts-icon')
|
||||
.removeClass('fa-caret-right')
|
||||
.addClass('fa-caret-down');
|
||||
},
|
||||
|
||||
// Toggle icon class.
|
||||
if ($transcriptsWrapperEl.hasClass('hidden')) {
|
||||
this.$el.find('.toggle-show-transcripts-icon').removeClass('fa-caret-down').addClass('fa-caret-right'); // eslint-disable-line max-len
|
||||
} else {
|
||||
this.$el.find('.toggle-show-transcripts-icon').removeClass('fa-caret-right').addClass('fa-caret-down'); // eslint-disable-line max-len
|
||||
}
|
||||
hideTranscripts: function() {
|
||||
// Hide transcript wrapper
|
||||
this.$el.find('.video-transcripts-wrapper').addClass('hidden');
|
||||
|
||||
// Update button text.
|
||||
HtmlUtils.setHtml(
|
||||
this.$el.find('.toggle-show-transcripts-button-text'),
|
||||
StringUtils.interpolate(
|
||||
gettext('Show transcripts ({transcriptCount})'),
|
||||
{
|
||||
transcriptCount: this.transcripts.length
|
||||
}
|
||||
)
|
||||
);
|
||||
this.$el.find('.toggle-show-transcripts-icon')
|
||||
.removeClass('fa-caret-down')
|
||||
.addClass('fa-caret-right');
|
||||
},
|
||||
|
||||
validateTranscriptUpload: function(file) {
|
||||
@@ -130,7 +171,7 @@ define(
|
||||
},
|
||||
|
||||
chooseFile: function(event) {
|
||||
var $transcriptContainer = $(event.target).parents('.show-video-transcript-content'),
|
||||
var $transcriptContainer = $(event.target).parents('.video-transcript-content'),
|
||||
$transcriptUploadEl = $transcriptContainer.find('.upload-transcript-input');
|
||||
|
||||
$transcriptUploadEl.fileupload({
|
||||
@@ -150,7 +191,7 @@ define(
|
||||
|
||||
transcriptSelected: function(event, data) {
|
||||
var errorMessage,
|
||||
$transcriptContainer = $(event.target).parents('.show-video-transcript-content');
|
||||
$transcriptContainer = $(event.target).parents('.video-transcript-content');
|
||||
|
||||
errorMessage = this.validateTranscriptUpload(data.files[0]);
|
||||
if (!errorMessage) {
|
||||
@@ -168,7 +209,7 @@ define(
|
||||
transcriptUploadSucceeded: function(event, data) {
|
||||
var languageCode = data.formData.language_code,
|
||||
newLanguageCode = data.formData.new_language_code,
|
||||
$transcriptContainer = this.$el.find('.show-video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
$transcriptContainer = this.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
$transcriptContainer.attr('data-language-code', newLanguageCode);
|
||||
$transcriptContainer.find('.download-transcript-button').attr(
|
||||
@@ -197,7 +238,7 @@ define(
|
||||
transcriptUploadFailed: function(event, data) {
|
||||
var errorMessage,
|
||||
languageCode = data.formData.language_code,
|
||||
$transcriptContainer = this.$el.find('.show-video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
$transcriptContainer = this.$el.find('.video-transcript-content[data-language-code="' + languageCode + '"]'); // eslint-disable-line max-len
|
||||
|
||||
try {
|
||||
errorMessage = JSON.parse(data.jqXHR.responseText).error;
|
||||
@@ -211,6 +252,39 @@ define(
|
||||
this.renderMessage($transcriptContainer, 'failed', errorMessage);
|
||||
},
|
||||
|
||||
deleteTranscript: function(event) {
|
||||
var self = this,
|
||||
$transcriptEl = $(event.target).parents('.video-transcript-content'),
|
||||
languageCode = $transcriptEl.attr('data-language-code'),
|
||||
transcriptDeleteUrl = self.getTranscriptDeleteUrl(
|
||||
self.edxVideoID,
|
||||
languageCode,
|
||||
self.videoTranscriptSettings.transcript_delete_handler_url
|
||||
);
|
||||
|
||||
ViewUtils.confirmThenRunOperation(
|
||||
gettext('Are you sure you want to remove this transcript?'),
|
||||
gettext('If you remove this transcript, the transcript will not be available for any components that use this video.'), // eslint-disable-line max-len
|
||||
gettext('Remove'),
|
||||
function() {
|
||||
ViewUtils.runOperationShowingMessage(
|
||||
gettext('Removing'),
|
||||
function() {
|
||||
return $.ajax({
|
||||
url: transcriptDeleteUrl,
|
||||
type: 'DELETE'
|
||||
}).done(function() {
|
||||
// Update transcripts.
|
||||
self.transcripts = _.without(self.transcripts, languageCode);
|
||||
// re-render transcripts.
|
||||
self.render();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
clearMessage: function() {
|
||||
var $transcriptStatusesEl = this.$el.find('.transcript-upload-status-container');
|
||||
// Clear all message containers
|
||||
@@ -271,6 +345,12 @@ define(
|
||||
transcriptDownloadHandlerUrl: this.videoTranscriptSettings.transcript_download_handler_url
|
||||
})
|
||||
);
|
||||
|
||||
if (this.isCollapsed) {
|
||||
this.hideTranscripts();
|
||||
} else {
|
||||
this.showTranscripts();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
cursor:pointer
|
||||
}
|
||||
|
||||
.show-video-transcripts-wrapper {
|
||||
.video-transcripts-wrapper {
|
||||
display: block;
|
||||
|
||||
.button-link {
|
||||
@@ -37,7 +37,7 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.show-video-transcript-content {
|
||||
.video-transcript-content {
|
||||
margin-top: ($baseline/2);
|
||||
|
||||
.transcript-upload-status-container {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class='show-video-transcripts-container'>
|
||||
<div class='video-transcripts-header'>
|
||||
<% if (transcripts.length) { %>
|
||||
<button class="button-link toggle-show-transcripts-button">
|
||||
<strong>
|
||||
@@ -11,10 +11,10 @@
|
||||
<% } else { %>
|
||||
<span class='transcripts-empty-text'><%- gettext('No transcript uploaded.') %></span>
|
||||
<% }%>
|
||||
<div class='show-video-transcripts-wrapper hidden'>
|
||||
<div class='video-transcripts-wrapper'>
|
||||
<% _.each(transcripts, function(transcriptLanguageCode){ %>
|
||||
<% selectedLanguageCodes = _.keys(_.omit(transcripts, transcriptLanguageCode)); %>
|
||||
<div class='show-video-transcript-content' data-edx-video-id="<%- edxVideoID %>" data-language-code="<%- transcriptLanguageCode %>">
|
||||
<div class='video-transcript-content' data-edx-video-id="<%- edxVideoID %>" data-language-code="<%- transcriptLanguageCode %>">
|
||||
<div class='transcript-upload-status-container'></div>
|
||||
<strong class='transcript-title'><%- StringUtils.interpolate(gettext('{transcriptClientTitle}_{transcriptLanguageCode}.{fileExtension}'), {transcriptClientTitle: transcriptClientTitle, transcriptLanguageCode: transcriptLanguageCode, fileExtension: transcriptFileFormat}) %></strong>
|
||||
<select class='transcript-language-menu'>
|
||||
@@ -35,6 +35,8 @@
|
||||
</a>
|
||||
<span class='transcript-actions-separator'> | </span>
|
||||
<button class="button-link upload-transcript-button"><%- gettext('Replace') %></button>
|
||||
<span class='transcript-actions-separator'> | </span>
|
||||
<button class="button-link delete-transcript-button"><%- gettext('Delete') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
||||
|
||||
@@ -143,6 +143,9 @@ urlpatterns = [
|
||||
contentstore.views.transcript_download_handler, name='transcript_download_handler'),
|
||||
url(r'^transcript_upload/{}$'.format(settings.COURSE_KEY_PATTERN),
|
||||
contentstore.views.transcript_upload_handler, name='transcript_upload_handler'),
|
||||
url(r'^transcript_delete/{}(?:/(?P<edx_video_id>[-\w]+))?(?:/(?P<language_code>[^/]*))?$'.format(
|
||||
settings.COURSE_KEY_PATTERN
|
||||
), contentstore.views.transcript_delete_handler, name='transcript_delete_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),
|
||||
|
||||
Reference in New Issue
Block a user