Commit 6634b92c by Mushtaq Ali

Transcript organization credentials UI - EDUCATOR-1126

parent 8089a0db
...@@ -31,6 +31,8 @@ from edxval.api import ( ...@@ -31,6 +31,8 @@ from edxval.api import (
get_transcript_preferences, get_transcript_preferences,
create_or_update_transcript_preferences, create_or_update_transcript_preferences,
remove_transcript_preferences, remove_transcript_preferences,
get_transcript_credentials_state_for_org,
update_transcript_credentials_state_for_org,
) )
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
from openedx.core.djangoapps.video_config.models import VideoTranscriptEnabledFlag from openedx.core.djangoapps.video_config.models import VideoTranscriptEnabledFlag
...@@ -44,7 +46,13 @@ from util.json_request import JsonResponse, expect_json ...@@ -44,7 +46,13 @@ from util.json_request import JsonResponse, expect_json
from .course import get_course_and_check_access from .course import get_course_and_check_access
__all__ = ['videos_handler', 'video_encodings_download', 'video_images_handler', 'transcript_preferences_handler'] __all__ = [
'videos_handler',
'video_encodings_download',
'video_images_handler',
'transcript_preferences_handler',
'transcript_credentials_handler'
]
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
...@@ -380,6 +388,32 @@ def transcript_preferences_handler(request, course_key_string): ...@@ -380,6 +388,32 @@ def transcript_preferences_handler(request, course_key_string):
return JsonResponse() return JsonResponse()
@expect_json
@login_required
@require_POST
def transcript_credentials_handler(request, course_key_string):
"""
JSON view handler to post the transcript organization credentials.
Arguments:
request: WSGI request object
course_key_string: string for course key
Returns: An empty success response or 404 if transcript feature is not enabled
"""
course_key = CourseKey.from_string(course_key_string)
if not VideoTranscriptEnabledFlag.feature_enabled(course_key):
return HttpResponseNotFound()
org = course_key.org
provider = request.json.get('provider')
# TODO: Send organization credentials to edx-pipeline end point.
credentials = update_transcript_credentials_state_for_org(org, provider, exists=True)
return JsonResponse()
@login_required @login_required
@require_GET @require_GET
def video_encodings_download(request, course_key_string): def video_encodings_download(request, course_key_string):
...@@ -589,7 +623,8 @@ def videos_index_html(course): ...@@ -589,7 +623,8 @@ def videos_index_html(course):
}, },
'is_video_transcript_enabled': is_video_transcript_enabled, 'is_video_transcript_enabled': is_video_transcript_enabled,
'video_transcript_settings': None, 'video_transcript_settings': None,
'active_transcript_preferences': None 'active_transcript_preferences': None,
'transcript_credentials': None
} }
if is_video_transcript_enabled: if is_video_transcript_enabled:
...@@ -598,9 +633,15 @@ def videos_index_html(course): ...@@ -598,9 +633,15 @@ def videos_index_html(course):
'transcript_preferences_handler', 'transcript_preferences_handler',
unicode(course.id) unicode(course.id)
), ),
'transcript_credentials_handler_url': reverse_course_url(
'transcript_credentials_handler',
unicode(course.id)
),
'transcription_plans': get_3rd_party_transcription_plans(), 'transcription_plans': get_3rd_party_transcription_plans(),
} }
context['active_transcript_preferences'] = get_transcript_preferences(unicode(course.id)) context['active_transcript_preferences'] = get_transcript_preferences(unicode(course.id))
# Cached state for transcript providers' credentials (org-specific)
context['transcript_credentials'] = get_transcript_credentials_state_for_org(course.id.org)
return render_to_response('videos_index.html', context) return render_to_response('videos_index.html', context)
......
...@@ -15,6 +15,7 @@ define([ ...@@ -15,6 +15,7 @@ define([
videoSupportedFileFormats, videoSupportedFileFormats,
videoUploadMaxFileSizeInGB, videoUploadMaxFileSizeInGB,
activeTranscriptPreferences, activeTranscriptPreferences,
transcriptOrganizationCredentials,
videoTranscriptSettings, videoTranscriptSettings,
isVideoTranscriptEnabled, isVideoTranscriptEnabled,
videoImageSettings videoImageSettings
...@@ -27,6 +28,7 @@ define([ ...@@ -27,6 +28,7 @@ define([
videoUploadMaxFileSizeInGB: videoUploadMaxFileSizeInGB, videoUploadMaxFileSizeInGB: videoUploadMaxFileSizeInGB,
videoImageSettings: videoImageSettings, videoImageSettings: videoImageSettings,
activeTranscriptPreferences: activeTranscriptPreferences, activeTranscriptPreferences: activeTranscriptPreferences,
transcriptOrganizationCredentials: transcriptOrganizationCredentials,
videoTranscriptSettings: videoTranscriptSettings, videoTranscriptSettings: videoTranscriptSettings,
isVideoTranscriptEnabled: isVideoTranscriptEnabled, isVideoTranscriptEnabled: isVideoTranscriptEnabled,
onFileUploadDone: function(activeVideos) { onFileUploadDone: function(activeVideos) {
......
...@@ -43,7 +43,7 @@ define( ...@@ -43,7 +43,7 @@ define(
activeTranscriptPreferences: {}, activeTranscriptPreferences: {},
videoTranscriptSettings: { videoTranscriptSettings: {
transcript_preferences_handler_url: '', transcript_preferences_handler_url: '',
transcription_plans: {} transcription_plans: null
}, },
isVideoTranscriptEnabled: isVideoTranscriptEnabled isVideoTranscriptEnabled: isVideoTranscriptEnabled
}); });
......
...@@ -8,10 +8,19 @@ define( ...@@ -8,10 +8,19 @@ define(
courseVideoSettingsView, courseVideoSettingsView,
renderCourseVideoSettingsView, renderCourseVideoSettingsView,
destroyCourseVideoSettingsView, destroyCourseVideoSettingsView,
verifyTranscriptPreferences,
verifyTranscriptPreferencesView,
verifyOrganizationCredentialsView,
verifyOrganizationCredentialField,
verifyMessage,
verifyPreferanceErrorState, verifyPreferanceErrorState,
selectPreference, selectPreference,
chooseProvider, verifyProviderList,
verifyProviderSelectedView,
resetProvider,
changeProvider,
transcriptPreferencesUrl = '/transcript_preferences/course-v1:edX+DemoX+Demo_Course', transcriptPreferencesUrl = '/transcript_preferences/course-v1:edX+DemoX+Demo_Course',
transcriptCredentialsHandlerUrl = '/transcript_credentials/course-v1:edX+DemoX+Demo_Course',
activeTranscriptPreferences = { activeTranscriptPreferences = {
provider: 'Cielo24', provider: 'Cielo24',
cielo24_fidelity: 'PROFESSIONAL', cielo24_fidelity: 'PROFESSIONAL',
...@@ -21,6 +30,10 @@ define( ...@@ -21,6 +30,10 @@ define(
preferred_languages: ['fr', 'en'], preferred_languages: ['fr', 'en'],
modified: '2017-08-27T12:28:17.421260Z' modified: '2017-08-27T12:28:17.421260Z'
}, },
transcriptOrganizationCredentials = {
Cielo24: true,
'3PlayMedia': true
},
transcriptionPlans = { transcriptionPlans = {
'3PlayMedia': { '3PlayMedia': {
languages: { languages: {
...@@ -72,15 +85,37 @@ define( ...@@ -72,15 +85,37 @@ define(
}, },
display_name: 'Cielo24' display_name: 'Cielo24'
} }
},
providers = {
none: {
key: 'none',
value: '',
displayName: 'N/A'
},
Cielo24: {
key: 'Cielo24',
value: 'Cielo24',
displayName: 'Cielo24'
},
'3PlayMedia': {
key: '3PlayMedia',
value: '3PlayMedia',
displayName: '3Play Media'
}
}; };
renderCourseVideoSettingsView = function(activeTranscriptPreferencesData, transcriptionPlansData) { renderCourseVideoSettingsView = function(activeTranscriptPreferencesData, transcriptionPlansData, transcriptOrganizationCredentialsData) { // eslint-disable-line max-len
// First destroy old referance to the view if present.
destroyCourseVideoSettingsView();
courseVideoSettingsView = new CourseVideoSettingsView({ courseVideoSettingsView = new CourseVideoSettingsView({
activeTranscriptPreferences: activeTranscriptPreferencesData || null, activeTranscriptPreferences: activeTranscriptPreferencesData || null,
videoTranscriptSettings: { videoTranscriptSettings: {
transcript_preferences_handler_url: transcriptPreferencesUrl, transcript_preferences_handler_url: transcriptPreferencesUrl,
transcript_credentials_handler_url: transcriptCredentialsHandlerUrl,
transcription_plans: transcriptionPlansData || null transcription_plans: transcriptionPlansData || null
} },
transcriptOrganizationCredentials: transcriptOrganizationCredentialsData || null
}); });
$courseVideoSettingsEl = courseVideoSettingsView.render().$el; $courseVideoSettingsEl = courseVideoSettingsView.render().$el;
}; };
...@@ -108,10 +143,99 @@ define( ...@@ -108,10 +143,99 @@ define(
$preference.change(); $preference.change();
}; };
chooseProvider = function(selectedProvider) { verifyMessage = function(state, message) {
var icon = state === 'error' ? 'fa-info-circle' : 'fa-check-circle';
expect($courseVideoSettingsEl.find('.course-video-settings-message-wrapper.' + state).html()).toEqual(
'<div class="course-video-settings-message">' +
'<span class="icon fa ' + icon + '" aria-hidden="true"></span>' +
'<span>' + message + '</span>' +
'</div>'
);
};
verifyProviderList = function(selectedProvider) {
var $transcriptProvidersListEl = $courseVideoSettingsEl.find('.transcript-provider-wrapper .transcript-provider-group'); // eslint-disable-line max-len
// Check N/A provider is selected.
expect($transcriptProvidersListEl.find('input[type=radio]:checked').val()).toEqual(selectedProvider.value); // eslint-disable-line max-len
_.each(providers, function(provider, key) {
$transcriptProvidersListEl.find('label[for=transcript-provider-' + key + ']').val(provider.displayName); // eslint-disable-line max-len
});
};
verifyTranscriptPreferences = function() {
expect($courseVideoSettingsEl.find('#transcript-turnaround').val()).toEqual(
activeTranscriptPreferences.cielo24_turnaround
);
expect($courseVideoSettingsEl.find('#transcript-fidelity').val()).toEqual(
activeTranscriptPreferences.cielo24_fidelity
);
expect($courseVideoSettingsEl.find('.transcript-language-container').length).toEqual(
activeTranscriptPreferences.preferred_languages.length
);
// Now check values are assigned correctly.
expect(courseVideoSettingsView.selectedTurnaroundPlan, activeTranscriptPreferences.cielo24_turnaround);
expect(courseVideoSettingsView.selectedFidelityPlan, activeTranscriptPreferences.cielo24_fidelity);
expect(courseVideoSettingsView.selectedLanguages, activeTranscriptPreferences.preferred_languages);
};
verifyProviderSelectedView = function() {
// Verify provider
expect(
$courseVideoSettingsEl.find('.selected-transcript-provider .title').html()
).toEqual(courseVideoSettingsView.selectedProvider);
expect($courseVideoSettingsEl.find('.selected-transcript-provider .action-change-provider')).toExist();
expect(
$courseVideoSettingsEl.find('.selected-transcript-provider .action-change-provider .sr').html()
).toEqual('Press change to change selected transcript provider.');
};
verifyTranscriptPreferencesView = function() {
expect($courseVideoSettingsEl.find('.course-video-transcript-preferances-wrapper')).toExist();
};
verifyOrganizationCredentialsView = function() {
expect($courseVideoSettingsEl.find('.organization-credentials-content')).toExist();
};
verifyOrganizationCredentialField = function(fieldName, label) {
var elementSelector = courseVideoSettingsView.selectedProvider + '-' + fieldName;
// Verify that correct label is shown.
expect(
$courseVideoSettingsEl.find('.' + elementSelector + '-wrapper label .title').html()
).toEqual(label);
// Verify that credential field is shown.
expect(
$courseVideoSettingsEl.find('.' + elementSelector + '-wrapper .' + elementSelector)
).toExist();
};
changeProvider = function(selectedProvider) {
// If Provider Selected view is show, first click on "Change Provider" button to
// show all list of providers.
if ($courseVideoSettingsEl.find('.selected-transcript-provider').length) {
$courseVideoSettingsEl.find('.selected-transcript-provider .action-change-provider').click();
}
$courseVideoSettingsEl.find('#transcript-provider-' + selectedProvider).click(); $courseVideoSettingsEl.find('#transcript-provider-' + selectedProvider).click();
}; };
resetProvider = function() {
var requests = AjaxHelpers.requests(this);
// Set no provider selected
changeProvider('none');
$courseVideoSettingsEl.find('.action-update-course-video-settings').click();
AjaxHelpers.expectRequest(
requests,
'DELETE',
transcriptPreferencesUrl
);
// Send successful empty content response.
AjaxHelpers.respondWithJson(requests, {});
};
beforeEach(function() { beforeEach(function() {
setFixtures( setFixtures(
'<div class="video-transcript-settings-wrapper"></div>' + '<div class="video-transcript-settings-wrapper"></div>' +
...@@ -148,17 +272,10 @@ define( ...@@ -148,17 +272,10 @@ define(
}); });
it('does not populate transcription plans if transcription plans are not provided', function() { it('does not populate transcription plans if transcription plans are not provided', function() {
// First detroy old referance to the view.
destroyCourseVideoSettingsView();
// Create view with empty data. // Create view with empty data.
renderCourseVideoSettingsView(null, null); renderCourseVideoSettingsView();
// Checking turnaround is sufficient to check preferences are are shown or not.
expect($courseVideoSettingsEl.find('.transcript-provider-group').html()).toEqual(''); expect($courseVideoSettingsEl.find('.transcript-turnaround-wrapper')).not.toExist();
expect($courseVideoSettingsEl.find('.transcript-turnaround').html()).toEqual('');
expect($courseVideoSettingsEl.find('.transcript-fidelity').html()).toEqual('');
expect($courseVideoSettingsEl.find('.video-source-language').html()).toEqual('');
expect($courseVideoSettingsEl.find('.transcript-language-menu').html()).toEqual('');
}); });
it('populates transcription plans correctly', function() { it('populates transcription plans correctly', function() {
...@@ -169,39 +286,17 @@ define( ...@@ -169,39 +286,17 @@ define(
it('populates active preferances correctly', function() { it('populates active preferances correctly', function() {
// First check preferance are selected correctly in HTML. // First check preferance are selected correctly in HTML.
expect($courseVideoSettingsEl.find('.transcript-provider-group input:checked').val()).toEqual( verifyTranscriptPreferences();
activeTranscriptPreferences.provider
);
expect($courseVideoSettingsEl.find('.transcript-turnaround').val()).toEqual(
activeTranscriptPreferences.cielo24_turnaround
);
expect($courseVideoSettingsEl.find('.transcript-fidelity').val()).toEqual(
activeTranscriptPreferences.cielo24_fidelity
);
expect($courseVideoSettingsEl.find('.video-source-language').val()).toEqual(
activeTranscriptPreferences.video_source_language
);
expect($courseVideoSettingsEl.find('.transcript-language-container').length).toEqual(
activeTranscriptPreferences.preferred_languages.length
);
// Now check values are assigned correctly.
expect(courseVideoSettingsView.selectedProvider, activeTranscriptPreferences.provider);
expect(courseVideoSettingsView.selectedTurnaroundPlan, activeTranscriptPreferences.cielo24_turnaround);
expect(courseVideoSettingsView.selectedFidelityPlan, activeTranscriptPreferences.cielo24_fidelity);
expect(
courseVideoSettingsView.selectedSourceLanguage,
activeTranscriptPreferences.video_source_language
);
expect(courseVideoSettingsView.selectedLanguages, activeTranscriptPreferences.preferred_languages);
}); });
it('shows video source language directly in case of 3Play provider', function() { it('shows video source language directly in case of 3Play provider', function() {
var sourceLanguages, var sourceLanguages,
selectedProvider = '3PlayMedia'; selectedProvider = '3PlayMedia';
// Select CIELIO24 provider renderCourseVideoSettingsView(null, transcriptionPlans, transcriptOrganizationCredentials);
chooseProvider(selectedProvider);
// Select provider
changeProvider(selectedProvider);
expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider); expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider);
// Verify source langauges menu is shown. // Verify source langauges menu is shown.
...@@ -219,10 +314,10 @@ define( ...@@ -219,10 +314,10 @@ define(
selectedProvider = 'Cielo24', selectedProvider = 'Cielo24',
selectedFidelity = 'PROFESSIONAL'; selectedFidelity = 'PROFESSIONAL';
renderCourseVideoSettingsView(null, transcriptionPlans); renderCourseVideoSettingsView(null, transcriptionPlans, transcriptOrganizationCredentials);
// Select CIELIO24 provider // Select provider
chooseProvider(selectedProvider); changeProvider(selectedProvider);
expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider); expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider);
// Verify source language is not shown. // Verify source language is not shown.
...@@ -254,8 +349,10 @@ define( ...@@ -254,8 +349,10 @@ define(
selectedProvider = 'Cielo24', selectedProvider = 'Cielo24',
selectedFidelity = 'PROFESSIONAL'; selectedFidelity = 'PROFESSIONAL';
// Select CIELIO24 provider renderCourseVideoSettingsView(null, transcriptionPlans, transcriptOrganizationCredentials);
chooseProvider(selectedProvider);
// Select provider
changeProvider(selectedProvider);
expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider); expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider);
// Select fidelity // Select fidelity
...@@ -283,8 +380,10 @@ define( ...@@ -283,8 +380,10 @@ define(
selectedProvider = 'Cielo24', selectedProvider = 'Cielo24',
selectedFidelity = 'MECHANICAL'; selectedFidelity = 'MECHANICAL';
// Select CIELIO24 provider renderCourseVideoSettingsView(null, transcriptionPlans, transcriptOrganizationCredentials);
chooseProvider(selectedProvider);
// Select provider
changeProvider(selectedProvider);
expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider); expect(courseVideoSettingsView.selectedProvider).toEqual(selectedProvider);
// Select fidelity // Select fidelity
...@@ -332,37 +431,16 @@ define( ...@@ -332,37 +431,16 @@ define(
}); });
// Verify that success message is shown. // Verify that success message is shown.
expect($courseVideoSettingsEl.find('.course-video-settings-message-wrapper.success').html()).toEqual( verifyMessage('success', 'Settings updated');
'<div class="course-video-settings-message">' +
'<span class="icon fa fa-check-circle" aria-hidden="true"></span>' +
'<span>Settings updated</span>' +
'</div>'
);
}); });
it('removes transcript settings on update settings button click when no provider is selected', function() { it('removes transcript settings on update settings button click when no provider is selected', function() {
var requests = AjaxHelpers.requests(this); // Reset to N/A provider
resetProvider();
// Set no provider selected verifyProviderList(providers.none);
courseVideoSettingsView.selectedProvider = null;
$courseVideoSettingsEl.find('.action-update-course-video-settings').click();
AjaxHelpers.expectRequest(
requests,
'DELETE',
transcriptPreferencesUrl
);
// Send successful empty content response.
AjaxHelpers.respondWithJson(requests, {});
// Verify that success message is shown. // Verify that success message is shown.
expect($courseVideoSettingsEl.find('.course-video-settings-message-wrapper.success').html()).toEqual( verifyMessage('success', 'Settings updated');
'<div class="course-video-settings-message">' +
'<span class="icon fa fa-check-circle" aria-hidden="true"></span>' +
'<span>Settings updated</span>' +
'</div>'
);
}); });
it('shows error message if server sends error', function() { it('shows error message if server sends error', function() {
...@@ -390,12 +468,7 @@ define( ...@@ -390,12 +468,7 @@ define(
}); });
// Verify that error message is shown. // Verify that error message is shown.
expect($courseVideoSettingsEl.find('.course-video-settings-message-wrapper.error').html()).toEqual( verifyMessage('error', 'Error message');
'<div class="course-video-settings-message">' +
'<span class="icon fa fa-info-circle" aria-hidden="true"></span>' +
'<span>Error message</span>' +
'</div>'
);
}); });
it('implies preferences are required if not selected when saving preferances', function() { it('implies preferences are required if not selected when saving preferances', function() {
...@@ -423,8 +496,274 @@ define( ...@@ -423,8 +496,274 @@ define(
verifyPreferanceErrorState($courseVideoSettingsEl.find('.transcript-languages-wrapper'), false); verifyPreferanceErrorState($courseVideoSettingsEl.find('.transcript-languages-wrapper'), false);
}); });
it('shows provider selected view if active provider is present', function() {
var $selectedProviderContainerEl = $courseVideoSettingsEl.find('.transcript-provider-wrapper .selected-transcript-provider'); // eslint-disable-line max-len
expect($selectedProviderContainerEl.find('span').html()).toEqual(courseVideoSettingsView.selectedProvider); // eslint-disable-line max-len
expect($selectedProviderContainerEl.find('button.action-change-provider')).toExist();
// Verify provider list view is not shown.
expect($courseVideoSettingsEl.find('.transcript-provider-wrapper .transcript-provider-group')).not.toExist(); // eslint-disable-line max-len
});
it('does not show transcript preferences or organization credentials if N/A provider is saved', function() {
renderCourseVideoSettingsView(null, transcriptionPlans);
// Check N/A provider
resetProvider();
verifyProviderList(providers.none);
// Verify selected provider view is not shown.
expect($courseVideoSettingsEl.find('.transcript-provider-wrapper .selected-transcript-provider')).not.toExist(); // eslint-disable-line max-len
});
it('does not show transcript preferences or organization credentials if N/A provider is checked', function() { // eslint-disable-line max-len
renderCourseVideoSettingsView(null, transcriptionPlans);
// Check N/A provider
resetProvider();
verifyProviderList(providers.none);
// Verify selected provider view is not shown.
expect($courseVideoSettingsEl.find('.transcript-provider-wrapper .selected-transcript-provider')).not.toExist(); // eslint-disable-line max-len
// Verify transcript preferences are not shown.
expect($courseVideoSettingsEl.find('.course-video-transcript-preferances-wrapper')).not.toExist();
// Verify org credentials are not shown.
expect($courseVideoSettingsEl.find('.organization-credentials-content')).not.toExist();
});
it('shows organization credentials when organization credentials for selected provider are not present', function() { // eslint-disable-line max-len
renderCourseVideoSettingsView(null, transcriptionPlans);
// Check Cielo24 provider
changeProvider(providers.Cielo24.key);
verifyProviderList(providers.Cielo24);
// Verify organization credentials are shown.
verifyOrganizationCredentialsView();
// Verify transcript preferences are not shown.
expect($courseVideoSettingsEl.find('.course-video-transcript-preferances-wrapper')).not.toExist();
});
it('shows transcript preferences when organization credentials for selected provider are present', function() { // eslint-disable-line max-len
renderCourseVideoSettingsView(null, transcriptionPlans, transcriptOrganizationCredentials);
// Check Cielo24 provider
changeProvider('Cielo24');
verifyProviderList(providers.Cielo24);
// Verify organization credentials are not shown.
expect($courseVideoSettingsEl.find('.organization-credentials-content')).not.toExist();
// Verify transcript preferences are shown.
verifyTranscriptPreferencesView();
});
it('shows organization credentials view if clicked on change provider button', function() {
// Verify organization credentials view is not shown initially.
expect($courseVideoSettingsEl.find('.organization-credentials-content')).not.toExist();
verifyProviderSelectedView();
// Click change button to render organization credentials view.
$courseVideoSettingsEl.find('.action-change-provider').click();
// Verify organization credentials is now shown.
verifyOrganizationCredentialsView();
});
it('shows api secret input field if selected provider is 3Play Media', function() {
// Set selected provider to 3Play Media
changeProvider('3PlayMedia');
// Click change button to render organization credentials view.
$courseVideoSettingsEl.find('.action-change-provider').click();
// Verify 3play api secret and api key are present.
verifyOrganizationCredentialField('api-secret', 'API Secret');
verifyOrganizationCredentialField('api-key', 'API Key');
});
it('does not show api secret input field if selected provider is not 3Play Media', function() {
verifyProviderSelectedView();
// Click change button to render organization credentials view.
$courseVideoSettingsEl.find('.action-change-provider').click();
// Verify 3Play Media api secret is not present.
expect(
$courseVideoSettingsEl.find('.' + courseVideoSettingsView.selectedProvider + '-api-secret')
).not.toExist();
// Verify api key is present.
verifyOrganizationCredentialField('api-key', 'API Key');
});
it('shows warning message when changing organization credentials if present already', function() {
// Set selectedProvider organization credentials.
courseVideoSettingsView.transcriptOrganizationCredentials[courseVideoSettingsView.selectedProvider] = true; // eslint-disable-line max-len
verifyProviderSelectedView();
// Click change button to render organization credentials view.
$courseVideoSettingsEl.find('.action-change-provider').click();
// Verify credentials are shown
verifyOrganizationCredentialsView();
// Verify warning message is shown.
expect($courseVideoSettingsEl.find('.transcription-account-details.warning')).toExist();
// Verify message
expect($courseVideoSettingsEl.find('.transcription-account-details').html()).toEqual(
'<span>By entering the set of credntials below, ' +
'you will be overwriting your organization\'s credentials.</span>'
);
});
it('does not show warning message when changing organization credentials if not present already', function() { // eslint-disable-line max-len
verifyProviderSelectedView();
// Click change button to render organization credentials view.
$courseVideoSettingsEl.find('.action-change-provider').click();
// Verify warning message is not shown.
expect($courseVideoSettingsEl.find('.transcription-account-details.warning')).not.toExist();
// Initial detail message is shown instead.
expect($courseVideoSettingsEl.find('.transcription-account-details').html()).toEqual(
'<span>Please enter your organization\'s account information. ' +
'Remember that all courses in your organization will use this account.</span>'
);
});
it('shows validation errors if no organization credentials are provided when saving credentials', function() { // eslint-disable-line max-len
// Set selected provider to 3Play Media
changeProvider('3PlayMedia');
// Click save organization credentials button to save credentials.
$courseVideoSettingsEl.find('.action-update-org-credentials').click();
verifyPreferanceErrorState(
$courseVideoSettingsEl.find('.' + courseVideoSettingsView.selectedProvider + '-api-key-wrapper'),
true
);
verifyPreferanceErrorState(
$courseVideoSettingsEl.find('.' + courseVideoSettingsView.selectedProvider + '-api-secret-wrapper'),
true
);
});
it('saves organization credentials on clicking save credentials button', function() {
var requests = AjaxHelpers.requests(this);
verifyProviderSelectedView();
// Click change button to render organization credentials view.
$courseVideoSettingsEl.find('.action-change-provider').click();
// Set organization credentials so as to pass validations.
$courseVideoSettingsEl.find('.' + courseVideoSettingsView.selectedProvider + '-api-key').val('testkey');
// Click save organization credentials button to save credentials.
$courseVideoSettingsEl.find('.action-update-org-credentials').click();
AjaxHelpers.expectRequest(
requests,
'POST',
transcriptCredentialsHandlerUrl,
JSON.stringify({
provider: activeTranscriptPreferences.provider,
global: false
})
);
// Send empty response.
AjaxHelpers.respondWithJson(requests, {});
// Verify that success message is shown.
verifyMessage(
'success',
transcriptionPlans[courseVideoSettingsView.selectedProvider].display_name + ' credentials saved'
);
});
it('shows selected provider view afer organization credentials saved', function() {
var requests = AjaxHelpers.requests(this);
renderCourseVideoSettingsView(null, transcriptionPlans);
// Verify selected provider view is not shown.
expect(
$courseVideoSettingsEl.find('.transcript-provider-wrapper .selected-transcript-provider')
).not.toExist();
// Verify provider list view is shown.
verifyProviderList(providers.none);
// Check Cielo24 provider
changeProvider('Cielo24');
verifyProviderList(providers.Cielo24);
// Set organization credentials so as to pass validations.
$courseVideoSettingsEl.find('.' + courseVideoSettingsView.selectedProvider + '-api-key').val('testkey');
// Click save organization credentials button to save credentials.
$courseVideoSettingsEl.find('.action-update-org-credentials').click();
AjaxHelpers.expectRequest(
requests,
'POST',
transcriptCredentialsHandlerUrl,
JSON.stringify({
provider: activeTranscriptPreferences.provider,
global: false
})
);
// Send empty response.
AjaxHelpers.respondWithJson(requests, {});
// Verify that success message is shown.
verifyMessage(
'success',
transcriptionPlans[courseVideoSettingsView.selectedProvider].display_name + ' credentials saved'
);
// Shows selected provider view after credentials are saved.
verifyProviderSelectedView();
// Verify provider list view is not shown.
expect(
$courseVideoSettingsEl.find('.transcript-provider-wrapper .transcript-provider-group')
).not.toExist();
});
it('shows error message on saving organization credentials if server sends error', function() {
var requests = AjaxHelpers.requests(this);
verifyProviderSelectedView();
// Click change button to render organization credentials view.
$courseVideoSettingsEl.find('.action-change-provider').click();
// Set organization credentials so as to pass validations.
$courseVideoSettingsEl.find('.' + courseVideoSettingsView.selectedProvider + '-api-key').val('testkey');
// Click save organization credentials button to save credentials.
$courseVideoSettingsEl.find('.action-update-org-credentials').click();
AjaxHelpers.expectRequest(
requests,
'POST',
transcriptCredentialsHandlerUrl,
JSON.stringify({
provider: activeTranscriptPreferences.provider,
global: false
})
);
// Send error response.
AjaxHelpers.respondWithError(requests, 400, {
error: 'Error message'
});
// Verify that error message is shown.
verifyMessage('error', 'Error message');
});
// TODO: Add more tests like clicking on add language, remove and their scenarios and some other tests // TODO: Add more tests like clicking on add language, remove and their scenarios and some other tests
// like N/A selected, specific provider selected tests, specific preferance selected tests etc. // for specific preferance selected tests etc. - See EDUCATOR-1478
}); });
} }
); );
...@@ -42,6 +42,7 @@ define([ ...@@ -42,6 +42,7 @@ define([
this.concurrentUploadLimit = options.concurrentUploadLimit || 0; this.concurrentUploadLimit = options.concurrentUploadLimit || 0;
this.postUrl = options.postUrl; this.postUrl = options.postUrl;
this.activeTranscriptPreferences = options.activeTranscriptPreferences; this.activeTranscriptPreferences = options.activeTranscriptPreferences;
this.transcriptOrganizationCredentials = options.transcriptOrganizationCredentials;
this.videoTranscriptSettings = options.videoTranscriptSettings; this.videoTranscriptSettings = options.videoTranscriptSettings;
this.isVideoTranscriptEnabled = options.isVideoTranscriptEnabled; this.isVideoTranscriptEnabled = options.isVideoTranscriptEnabled;
this.videoSupportedFileFormats = options.videoSupportedFileFormats; this.videoSupportedFileFormats = options.videoSupportedFileFormats;
...@@ -85,6 +86,7 @@ define([ ...@@ -85,6 +86,7 @@ define([
if (this.isVideoTranscriptEnabled) { if (this.isVideoTranscriptEnabled) {
this.courseVideoSettingsView = new CourseVideoSettingsView({ this.courseVideoSettingsView = new CourseVideoSettingsView({
activeTranscriptPreferences: this.activeTranscriptPreferences, activeTranscriptPreferences: this.activeTranscriptPreferences,
transcriptOrganizationCredentials: this.transcriptOrganizationCredentials,
videoTranscriptSettings: this.videoTranscriptSettings videoTranscriptSettings: this.videoTranscriptSettings
}); });
this.courseVideoSettingsView.render(); this.courseVideoSettingsView.render();
......
...@@ -3,11 +3,20 @@ ...@@ -3,11 +3,20 @@
*/ */
define([ define([
'jquery', 'backbone', 'underscore', 'gettext', 'moment', 'jquery', 'backbone', 'underscore', 'gettext', 'moment',
'common/js/components/utils/view_utils',
'edx-ui-toolkit/js/utils/html-utils', 'edx-ui-toolkit/js/utils/html-utils',
'edx-ui-toolkit/js/utils/string-utils', 'edx-ui-toolkit/js/utils/string-utils',
'text!templates/course-video-settings.underscore' 'text!templates/course-video-settings.underscore',
'text!templates/course-video-transcript-preferences.underscore',
'text!templates/course-video-transcript-provider-empty.underscore',
'text!templates/course-video-transcript-provider-selected.underscore',
'text!templates/transcript-organization-credentials.underscore',
'text!templates/course-video-settings-update-settings-footer.underscore',
'text!templates/course-video-settings-update-org-credentials-footer.underscore'
], ],
function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSettingsTemplate) { function($, Backbone, _, gettext, moment, ViewUtils, HtmlUtils, StringUtils, TranscriptSettingsTemplate,
TranscriptPreferencesTemplate, TranscriptProviderEmptyStateTemplate, TranscriptProviderSelectedStateTemplate,
OrganizationCredentialsTemplate, UpdateSettingsFooterTemplate, OrganizationCredentialsFooterTemplate) {
'use strict'; 'use strict';
var CourseVideoSettingsView, var CourseVideoSettingsView,
...@@ -24,6 +33,8 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -24,6 +33,8 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
'change #video-source-language': 'videoSourceLanguageSelected', 'change #video-source-language': 'videoSourceLanguageSelected',
'click .action-add-language': 'languageSelected', 'click .action-add-language': 'languageSelected',
'click .action-remove-language': 'languageRemoved', 'click .action-remove-language': 'languageRemoved',
'click .action-change-provider': 'renderOrganizationCredentials',
'click .action-update-org-credentials': 'updateOrganizationCredentials',
'click .action-update-course-video-settings': 'updateCourseVideoSettings', 'click .action-update-course-video-settings': 'updateCourseVideoSettings',
'click .action-close-course-video-settings': 'closeCourseVideoSettings' 'click .action-close-course-video-settings': 'closeCourseVideoSettings'
}, },
...@@ -31,9 +42,17 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -31,9 +42,17 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
initialize: function(options) { initialize: function(options) {
var videoTranscriptSettings = options.videoTranscriptSettings; var videoTranscriptSettings = options.videoTranscriptSettings;
this.activeTranscriptionPlan = options.activeTranscriptPreferences; this.activeTranscriptionPlan = options.activeTranscriptPreferences;
this.transcriptOrganizationCredentials = _.extend({}, options.transcriptOrganizationCredentials);
this.availableTranscriptionPlans = videoTranscriptSettings.transcription_plans; this.availableTranscriptionPlans = videoTranscriptSettings.transcription_plans;
this.transcriptHandlerUrl = videoTranscriptSettings.transcript_preferences_handler_url; this.transcriptHandlerUrl = videoTranscriptSettings.transcript_preferences_handler_url;
this.transcriptCredentialsHandlerUrl = videoTranscriptSettings.transcript_credentials_handler_url;
this.template = HtmlUtils.template(TranscriptSettingsTemplate); this.template = HtmlUtils.template(TranscriptSettingsTemplate);
this.transcriptPreferencesTemplate = HtmlUtils.template(TranscriptPreferencesTemplate);
this.organizationCredentialsTemplate = HtmlUtils.template(OrganizationCredentialsTemplate);
this.organizationCredentialsFooterTemplate = HtmlUtils.template(OrganizationCredentialsFooterTemplate);
this.updateSettingsFooterTemplate = HtmlUtils.template(UpdateSettingsFooterTemplate);
this.transcriptProviderEmptyStateTemplate = HtmlUtils.template(TranscriptProviderEmptyStateTemplate);
this.transcriptProviderSelectedStateTemplate = HtmlUtils.template(TranscriptProviderSelectedStateTemplate);
this.setActiveTranscriptPlanData(); this.setActiveTranscriptPlanData();
this.selectedLanguages = []; this.selectedLanguages = [];
}, },
...@@ -49,7 +68,7 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -49,7 +68,7 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
// Click anywhere outside the course video settings pane would close the pane. // Click anywhere outside the course video settings pane would close the pane.
$(document).click(function(event) { $(document).click(function(event) {
// if the target of the click isn't the container nor a descendant of the contain // If the target of the click isn't the container nor a descendant of the contain
if (!self.$el.is(event.target) && self.$el.has(event.target).length === 0) { if (!self.$el.is(event.target) && self.$el.has(event.target).length === 0) {
self.closeCourseVideoSettings(); self.closeCourseVideoSettings();
} }
...@@ -158,9 +177,33 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -158,9 +177,33 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
}, },
providerSelected: function(event) { providerSelected: function(event) {
var $courseVideoSettingsContentEl = this.$el.find('.course-video-settings-content'),
dateModified = this.activeTranscriptionPlan ?
moment.utc(this.activeTranscriptionPlan.modified).format('ll') : '';
this.resetPlanData(); this.resetPlanData();
this.selectedProvider = event.target.value; this.selectedProvider = event.target.value;
this.renderPreferences();
if (!this.selectedProvider) {
// Hide organization credentials and transcript preferences views
$courseVideoSettingsContentEl.hide();
// Render footer
HtmlUtils.setHtml(
this.$el.find('.course-video-settings-footer'),
this.updateSettingsFooterTemplate({
dateModified: dateModified
})
);
return;
}
$courseVideoSettingsContentEl.show();
// If org provider specific credentials are present
if (this.transcriptOrganizationCredentials[this.selectedProvider]) {
this.renderTranscriptPreferences();
} else {
this.renderOrganizationCredentials();
}
}, },
languageSelected: function(event) { languageSelected: function(event) {
...@@ -187,43 +230,56 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -187,43 +230,56 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
$(event.target.parentElement).parent().remove(); $(event.target.parentElement).parent().remove();
// Remove language from selected languages. // Remove language from selected languages.
this.selectedLanguages = _.without(this.selectedLanguages, selectedLanguage); this.selectedLanguages = this.activeLanguages = _.without(this.selectedLanguages, selectedLanguage);
// Populate menu again to reflect latest changes. // Populate menu again to reflect latest changes.
this.populateLanguageMenu(); this.populateLanguageMenu();
}, },
renderProviders: function() { renderProviders: function(state) {
var self = this, var $transcriptProviderWrapperEl = this.$el.find('.transcript-provider-wrapper');
providerPlan = self.availableTranscriptionPlans, if (!state) {
$providerEl = self.$el.find('.transcript-provider-group'); state = this.selectedProvider ? 'selected' : 'empty'; // eslint-disable-line no-param-reassign
}
if (providerPlan) { // If no transcription plans are sentm return.
if (!this.availableTranscriptionPlans) {
return;
}
if (state === 'empty') {
HtmlUtils.setHtml( HtmlUtils.setHtml(
$providerEl, $transcriptProviderWrapperEl,
HtmlUtils.interpolateHtml( this.transcriptProviderEmptyStateTemplate({
HtmlUtils.HTML('<input type="radio" id="transcript-provider-none" name="transcript-provider" value="" {checked}/><label for="transcript-provider-none">{text}</label>'), // eslint-disable-line max-len providers: [
{ {
text: gettext('N/A'), key: 'none',
checked: self.selectedProvider === '' ? 'checked' : '' value: '',
} name: gettext('N/A'),
) checked: this.selectedProvider === '' ? 'checked' : ''
); },
_.each(providerPlan, function(providerObject, key) {
var checked = self.selectedProvider === key ? 'checked' : '';
HtmlUtils.append(
$providerEl,
HtmlUtils.interpolateHtml(
HtmlUtils.HTML('<input type="radio" id="transcript-provider-{value}" name="transcript-provider" value="{value}" {checked}/><label for="transcript-provider-{value}">{text}'), // eslint-disable-line max-len
{ {
text: providerObject.display_name, key: CIELO24,
value: key, value: CIELO24,
checked: checked name: this.availableTranscriptionPlans[CIELO24].display_name,
checked: this.selectedProvider === CIELO24 ? 'checked' : ''
},
{
key: THREE_PLAY_MEDIA,
value: THREE_PLAY_MEDIA,
name: this.availableTranscriptionPlans[THREE_PLAY_MEDIA].display_name,
checked: this.selectedProvider === THREE_PLAY_MEDIA ? 'checked' : ''
} }
) ]
); })
}); );
} else {
HtmlUtils.setHtml(
$transcriptProviderWrapperEl,
this.transcriptProviderSelectedStateTemplate({
selectedProvider: this.availableTranscriptionPlans[this.selectedProvider].display_name
})
);
this.renderTranscriptPreferences();
} }
}, },
...@@ -284,6 +340,10 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -284,6 +340,10 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
renderTargetLanguages: function() { renderTargetLanguages: function() {
var self = this, var self = this,
// Merge active and selected languages, this handles the case when active languages are present and
// user also has selected some languages but not saved, user changes organization credentials,
// both active and selected languages should be rendered.
selectedLanguages = _.union(self.activeLanguages, self.selectedLanguages),
$languagesPreferenceContainer = self.$el.find('.transcript-languages-wrapper'), $languagesPreferenceContainer = self.$el.find('.transcript-languages-wrapper'),
$languagesContainer = self.$el.find('.languages-container'); $languagesContainer = self.$el.find('.languages-container');
...@@ -292,9 +352,9 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -292,9 +352,9 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
$languagesContainer.empty(); $languagesContainer.empty();
// Show language container if source language is selected . // Show language container if source language is selected.
if (self.selectedVideoSourceLanguage) { if (self.selectedVideoSourceLanguage) {
_.each(self.activeLanguages, function(language) { _.each(selectedLanguages, function(language) {
// Only add if not in the list already. // Only add if not in the list already.
if (_.indexOf(self.selectedLanguages, language) === -1) { if (_.indexOf(self.selectedLanguages, language) === -1) {
self.selectedLanguages.push(language); self.selectedLanguages.push(language);
...@@ -386,14 +446,6 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -386,14 +446,6 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
} }
}, },
renderPreferences: function() {
this.renderProviders();
this.renderTurnaround();
this.renderFidelity();
this.renderSourceLanguages();
this.renderTargetLanguages();
},
addLanguage: function(language) { addLanguage: function(language) {
var $languagesContainer = this.$el.find('.languages-container'); var $languagesContainer = this.$el.find('.languages-container');
HtmlUtils.append( HtmlUtils.append(
...@@ -419,8 +471,9 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -419,8 +471,9 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
); );
}, },
updateSuccessResponseStatus: function(data) { updateSuccessResponseStatus: function(data, successMessage) {
var dateModified = data ? moment.utc(data.modified).format('ll') : ''; var dateModified = data ? moment.utc(data.modified).format('ll') : '';
successMessage = successMessage ? successMessage : gettext('Settings updated'); // eslint-disable-line no-param-reassign, no-unneeded-ternary, max-len
// Update last modified date // Update last modified date
if (dateModified) { if (dateModified) {
...@@ -436,7 +489,10 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -436,7 +489,10 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
); );
} }
this.renderResponseStatus(gettext('Settings updated'), 'success'); // Now re-render providers state.
this.renderProviders();
this.renderResponseStatus(successMessage, 'success');
// Sync ActiveUploadListView with latest active plan. // Sync ActiveUploadListView with latest active plan.
this.activeTranscriptionPlan = data; this.activeTranscriptionPlan = data;
Backbone.trigger('coursevideosettings:syncActiveTranscriptPreferences', this.activeTranscriptionPlan); Backbone.trigger('coursevideosettings:syncActiveTranscriptPreferences', this.activeTranscriptionPlan);
...@@ -548,6 +604,37 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -548,6 +604,37 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
return isValid; return isValid;
}, },
validateOrganizationCredentials: function() {
var $OrganizationApiSecretWrapperEl,
isValid = true,
$OrganizationApiKeyWrapperEl = this.$el.find('.' + this.selectedProvider + '-api-key-wrapper');
// Explicit None selected case.
if (this.selectedProvider === '') {
return false;
}
if ($OrganizationApiKeyWrapperEl.find('input').val() === '') {
isValid = false;
this.addErrorState($OrganizationApiKeyWrapperEl);
} else {
this.clearPreferenceErrorState($OrganizationApiKeyWrapperEl);
}
if (this.selectedProvider === THREE_PLAY_MEDIA) {
$OrganizationApiSecretWrapperEl = this.$el.find('.' + this.selectedProvider + '-api-secret-wrapper');
if ($OrganizationApiSecretWrapperEl.find('input').val() === '') {
isValid = false;
this.addErrorState($OrganizationApiSecretWrapperEl);
} else {
this.clearPreferenceErrorState($OrganizationApiSecretWrapperEl);
}
}
return isValid;
},
saveTranscriptPreferences: function() { saveTranscriptPreferences: function() {
var self = this, var self = this,
responseTranscriptPreferences; responseTranscriptPreferences;
...@@ -585,6 +672,42 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -585,6 +672,42 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
} }
}, },
saveOrganizationCredentials: function() {
var self = this;
// First clear response status if present already
this.clearResponseStatus();
// TODO: Send actual organization credentials.
$.postJSON(self.transcriptCredentialsHandlerUrl, {
provider: self.selectedProvider,
global: false // Do not trigger global AJAX error handler
}, function() {
self.$el.find('.organization-credentials-wrapper').hide();
// Update org credentials for selected provider
self.transcriptOrganizationCredentials[self.selectedProvider] = true;
self.updateSuccessResponseStatus(
self.activeTranscriptionPlan,
gettext('{selectedProvider} credentials saved').replace(
'{selectedProvider}',
self.availableTranscriptionPlans[self.selectedProvider].display_name
)
);
}).fail(function(jqXHR) {
if (jqXHR.responseText) {
self.updateFailResponseStatus(jqXHR.responseText);
}
});
},
updateOrganizationCredentials: function() {
if (this.validateOrganizationCredentials()) {
this.saveOrganizationCredentials();
}
},
updateCourseVideoSettings: function() { updateCourseVideoSettings: function() {
var $messageWrapperEl = this.$el.find('.course-video-settings-message-wrapper'); var $messageWrapperEl = this.$el.find('.course-video-settings-message-wrapper');
if (this.validateCourseVideoSettings()) { if (this.validateCourseVideoSettings()) {
...@@ -594,17 +717,74 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -594,17 +717,74 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
} }
}, },
renderOrganizationCredentials: function() {
var $courseVideoSettingsContentEl = this.$el.find('.course-video-settings-content');
// Render empty state providers view.
this.renderProviders('empty');
HtmlUtils.setHtml(
$courseVideoSettingsContentEl,
this.organizationCredentialsTemplate({
selectedProvider: {
key: this.selectedProvider,
name: this.availableTranscriptionPlans[this.selectedProvider].display_name
},
organizationCredentialsExists: this.transcriptOrganizationCredentials[this.selectedProvider],
CIELO24: CIELO24,
THREE_PLAY_MEDIA: THREE_PLAY_MEDIA
})
);
// Render footer
HtmlUtils.setHtml(
this.$el.find('.course-video-settings-footer'),
this.organizationCredentialsFooterTemplate({})
);
},
renderTranscriptPreferences: function() {
var $courseVideoSettingsContentEl = this.$el.find('.course-video-settings-content'),
dateModified = this.activeTranscriptionPlan ?
moment.utc(this.activeTranscriptionPlan.modified).format('ll') : '';
HtmlUtils.setHtml(
$courseVideoSettingsContentEl,
this.transcriptPreferencesTemplate({
selectedProvider: this.selectedProvider,
THREE_PLAY_MEDIA: THREE_PLAY_MEDIA
})
);
// Render transcript preferences.
this.renderTurnaround();
this.renderFidelity();
this.renderSourceLanguages();
this.renderTargetLanguages();
// Render footer
HtmlUtils.setHtml(
this.$el.find('.course-video-settings-footer'),
this.updateSettingsFooterTemplate({
dateModified: dateModified
})
);
},
render: function() { render: function() {
var dateModified = this.activeTranscriptionPlan ? var dateModified = this.activeTranscriptionPlan ?
moment.utc(this.activeTranscriptionPlan.modified).format('ll') : ''; moment.utc(this.activeTranscriptionPlan.modified).format('ll') : '';
HtmlUtils.setHtml(this.$el, this.template({}));
// Render footer
HtmlUtils.setHtml( HtmlUtils.setHtml(
this.$el, this.$el.find('.course-video-settings-footer'),
this.template({ this.updateSettingsFooterTemplate({
dateModified: dateModified dateModified: dateModified
}) })
); );
this.renderPreferences(); this.renderProviders();
this.registerCloseClickHandler(); this.registerCloseClickHandler();
this.setFixedCourseVideoSettingsPane(); this.setFixedCourseVideoSettingsPane();
...@@ -640,7 +820,7 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -640,7 +820,7 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
}, },
closeCourseVideoSettings: function() { closeCourseVideoSettings: function() {
// TODO: Slide out when closing settings pane. We may need to hide the view instead of destroying it. // TODO: Slide out when closing settings pane. See EDUCATOR-1477
// Trigger destroy transcript event. // Trigger destroy transcript event.
Backbone.trigger('coursevideosettings:destroyCourseVideoSettingsView'); Backbone.trigger('coursevideosettings:destroyCourseVideoSettingsView');
......
...@@ -83,6 +83,18 @@ ...@@ -83,6 +83,18 @@
border: solid 1px $state-danger-border; border: solid 1px $state-danger-border;
} }
.organization-credentials-content {
margin-top: ($baseline*1.6);
.org-credentials-wrapper input {
width: 75%;
margin: ($baseline*0.8) 0;
}
.action-update-org-credentials {
margin-top: ($baseline*1.6);
}
}
.transcript-preferance-wrapper { .transcript-preferance-wrapper {
margin-top: ($baseline*1.6); margin-top: ($baseline*1.6);
.icon.fa-info-circle { .icon.fa-info-circle {
...@@ -99,6 +111,7 @@ ...@@ -99,6 +111,7 @@
.error-info { .error-info {
@include font-size(16); @include font-size(16);
@include margin-left($baseline/2);
} }
.transcript-preferance-label { .transcript-preferance-label {
...@@ -108,10 +121,15 @@ ...@@ -108,10 +121,15 @@
display: block; display: block;
} }
.transcript-provider-group, .transcript-turnaround, .transcript-fidelity, .video-source-language { .transcript-provider-group, .transcript-turnaround, .transcript-fidelity, .video-source-language, .selected-transcript-provider {
margin-top: ($baseline*0.8); margin-top: ($baseline*0.8);
} }
.selected-transcript-provider {
.action-change-provider {
@include margin-left($baseline/2);
}
}
.transcript-provider-group { .transcript-provider-group {
input[type=radio] { input[type=radio] {
...@@ -128,6 +146,10 @@ ...@@ -128,6 +146,10 @@
display: none; display: none;
} }
.transcript-languages-wrapper .transcript-preferance-label {
display: inline-block;
}
.transcript-languages-container .languages-container { .transcript-languages-container .languages-container {
margin-top: ($baseline*0.8); margin-top: ($baseline*0.8);
.transcript-language-container { .transcript-language-container {
...@@ -148,6 +170,9 @@ ...@@ -148,6 +170,9 @@
.action-add-language { .action-add-language {
@include margin-left($baseline/4); @include margin-left($baseline/4);
} }
.error-info {
display: inline-block;
}
} }
} }
.transcript-language-menu, .video-source-language { .transcript-language-menu, .video-source-language {
...@@ -155,6 +180,22 @@ ...@@ -155,6 +180,22 @@
} }
} }
.transcription-account-details {
margin-top: ($baseline*0.8);
span {
@include font-size(15);
}
}
.transcription-account-details.warning {
background-color: $state-warning-bg;
padding: ($baseline/2);
}
.action-update-org-credentials {
margin-top: ($baseline*1.6);
}
.course-video-settings-footer { .course-video-settings-footer {
margin-top: ($baseline*1.6); margin-top: ($baseline*1.6);
.last-updated-text { .last-updated-text {
......
<button class='button action-update-org-credentials' aria-describedby='update-org-credentials-button-text'>
<%- gettext('Update Organization Credentials') %>
<span id='update-org-credentials-button-text' class='sr'><%-gettext('Press update organization credentials to update organization credentials') %></span>
</button>
<button class="button action-update-course-video-settings" aria-describedby='update-button-text'>
<%- gettext('Update Settings') %>
<span id='update-button-text' class='sr'><%-gettext('Press update settings to update course video settings') %></span>
</button>
<span class='last-updated-text'>
<%if (dateModified) { %>
<%- gettext('Last updated')%> <%- dateModified %>
<% } %>
</span>
...@@ -11,49 +11,8 @@ ...@@ -11,49 +11,8 @@
<div class='course-video-settings-wrapper'> <div class='course-video-settings-wrapper'>
<div class='course-video-settings-message-wrapper'></div> <div class='course-video-settings-message-wrapper'></div>
<span class="course-video-settings-title"><%- gettext('Course Video Settings') %></span> <span class="course-video-settings-title"><%- gettext('Course Video Settings') %></span>
<div class='transcript-preferance-wrapper transcript-provider-wrapper'> <div class='transcript-preferance-wrapper transcript-provider-wrapper'></div>
<label class='transcript-preferance-label' for='transcript-provider'><%- gettext('Transcript Provider') %><span class='error-icon' aria-hidden="true"></span></label> <div class='course-video-settings-content'></div>
<div class='transcript-provider-group' id='transcript-provider'></div> <div class='course-video-settings-footer'></div>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-turnaround-wrapper'>
<label class='transcript-preferance-label' for='transcript-turnaround'><%- gettext('Transcript Turnaround') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-turnaround' class='transcript-turnaround'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-fidelity-wrapper'>
<label class='transcript-preferance-label' for='transcript-fidelity'><%- gettext('Transcript Fidelity') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-fidelity' class='transcript-fidelity'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper video-source-language-wrapper'>
<label class='transcript-preferance-label' for='video-source-language'><%- gettext('Video Source Language') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='video-source-language' class='video-source-language' aria-labelledby="video-source-language-none"></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-languages-wrapper'>
<span class='transcript-preferance-label'><%- gettext('Transcript Languages') %><span class='error-icon' aria-hidden="true"></span></span>
<div class='transcript-languages-container'>
<div class='languages-container'></div>
<div class="transcript-language-menu-container">
<select class="transcript-language-menu" id="transcript-language" aria-labelledby="transcript-language-none"></select>
<div class="add-language-action">
<button class="button-link action-add-language"><%- gettext('Add') %><span class="sr"><%- gettext('Press Add to language') %></span></button>
<span class="error-info" aria-hidden="true"></span>
</div>
</div>
</div>
</div>
<div class='course-video-settings-footer'>
<button class="button button action-update-course-video-settings" aria-describedby='update-button-text'>
<%- gettext('Update Settings') %>
<span id='update-button-text' class='sr'><%-gettext('Press update settings to update course video settings') %></span>
</button>
<span class='last-updated-text'>
<%if (dateModified) { %>
<%- gettext('Last updated')%> <%- dateModified %>
<% } %>
</span>
</div>
</div> </div>
</div> </div>
<div class='course-video-transcript-preferances-wrapper'>
<div class='transcript-preferance-wrapper transcript-turnaround-wrapper'>
<label class='transcript-preferance-label' for='transcript-turnaround'><%- gettext('Transcript Turnaround') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-turnaround' class='transcript-turnaround'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-fidelity-wrapper'>
<label class='transcript-preferance-label' for='transcript-fidelity'><%- gettext('Transcript Fidelity') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-fidelity' class='transcript-fidelity'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper video-source-language-wrapper'>
<label class='transcript-preferance-label' for='video-source-language'><%- gettext('Video Source Language') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='video-source-language' class='video-source-language' aria-labelledby="video-source-language-none"></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-languages-wrapper'>
<span class='transcript-preferance-label'><%- gettext('Transcript Languages') %></span>
<span class='error-icon' aria-hidden="true"></span>
<div class='transcript-languages-container'>
<div class='languages-container'></div>
<div class="transcript-language-menu-container">
<select class="transcript-language-menu" id="transcript-language" aria-labelledby="transcript-language-none"></select>
<div class="add-language-action">
<button class="button-link action-add-language"><%- gettext('Add') %><span class="sr"><%- gettext('Press Add to language') %></span></button>
</div>
<span class="error-info" aria-hidden="true"></span>
</div>
</div>
</div>
</div>
<label class='transcript-preferance-label' for='transcript-provider'><%- gettext('Transcript Provider') %></label>
<div class="transcript-provider-group" id="transcript-provider">
<% for (var i = 0; i < providers.length; i++) { %>
<input type='radio' id='transcript-provider-<%- providers[i].key %>' name='transcript-provider' value='<%- providers[i].value %>' <%- providers[i].checked %>>
<label for='transcript-provider-<%- providers[i].key %>'><%- providers[i].name %></label>
<% } %>
</div>
<label class='transcript-preferance-label' for='transcript-provider'><%- gettext('Transcript Provider') %></label>
<div class='selected-transcript-provider'>
<span class='title'><%- selectedProvider %></span>
<button class='button-link action-change-provider' aria-describedby='change-provider-button-text'>
<%- gettext('Change') %>
<span id='change-provider-button-text' class='sr'><%-gettext('Press change to change selected transcript provider.') %></span>
</button>
</div>
<div class='organization-credentials-wrapper'>
<div class='organization-credentials-content'>
<label class='transcript-preferance-label selected-provider-account'><%- selectedProvider.name %> <%- gettext('Account') %></label>
<% if (organizationCredentialsExists) { %>
<div class='transcription-account-details warning'><span><%- gettext("By entering the set of credntials below, you will be overwriting your organization's credentials.") %></span></div>
<% } else { %>
<div class='transcription-account-details'><span><%- gettext("Please enter your organization's account information. Remember that all courses in your organization will use this account.") %></span></div>
<% } %>
<div class='transcript-preferance-wrapper org-credentials-wrapper <%- selectedProvider.key %>-api-key-wrapper'>
<label class='transcript-preferance-label' for='<%- selectedProvider.key %>-api-key'>
<span class='title'><%- gettext('API Key') %></span>
<span class='error-icon' aria-hidden="true"></span>
</label>
<div>
<input type='text' class='<%- selectedProvider.key %>-api-key'>
<span class='error-info' aria-hidden="true"></span>
</div>
</div>
<% if (selectedProvider.key === THREE_PLAY_MEDIA) { %>
<div class='transcript-preferance-wrapper org-credentials-wrapper <%- selectedProvider.key %>-api-secret-wrapper'>
<label class='transcript-preferance-label' for='<%- selectedProvider.key %>-api-secret'>
<span class='title'><%- gettext('API Secret') %></span>
<span class='error-icon' aria-hidden="true"></span>
</label>
<div>
<input type='text' class='<%- selectedProvider.key %>-api-secret'>
<span class='error-info' aria-hidden="true"></span>
</div>
</div>
<% } else { %>
<div class='transcript-preferance-wrapper org-credentials-wrapper <%- selectedProvider.key %>-username-wrapper'>
<label class='transcript-preferance-label' for='<%- selectedProvider.key %>-username'>
<span class='title'><%- gettext('Username') %></span>
<span class='error-icon' aria-hidden="true"></span>
</label>
<div>
<input type='text' class='<%- selectedProvider.key %>-username'>
<span class='error-info' aria-hidden="true"></span>
</div>
</div>
<% } %>
</div>
</div>
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
${video_supported_file_formats | n, dump_js_escaped_json}, ${video_supported_file_formats | n, dump_js_escaped_json},
${video_upload_max_file_size | n, dump_js_escaped_json}, ${video_upload_max_file_size | n, dump_js_escaped_json},
${active_transcript_preferences | n, dump_js_escaped_json}, ${active_transcript_preferences | n, dump_js_escaped_json},
${transcript_credentials | n, dump_js_escaped_json},
${video_transcript_settings | n, dump_js_escaped_json}, ${video_transcript_settings | n, dump_js_escaped_json},
${is_video_transcript_enabled | n, dump_js_escaped_json}, ${is_video_transcript_enabled | n, dump_js_escaped_json},
${video_image_settings | n, dump_js_escaped_json} ${video_image_settings | n, dump_js_escaped_json}
......
...@@ -141,6 +141,8 @@ urlpatterns = [ ...@@ -141,6 +141,8 @@ urlpatterns = [
contentstore.views.video_images_handler, name='video_images_handler'), contentstore.views.video_images_handler, name='video_images_handler'),
url(r'^transcript_preferences/{}$'.format(settings.COURSE_KEY_PATTERN), url(r'^transcript_preferences/{}$'.format(settings.COURSE_KEY_PATTERN),
contentstore.views.transcript_preferences_handler, name='transcript_preferences_handler'), 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'^video_encodings_download/{}$'.format(settings.COURSE_KEY_PATTERN), url(r'^video_encodings_download/{}$'.format(settings.COURSE_KEY_PATTERN),
contentstore.views.video_encodings_download, name='video_encodings_download'), contentstore.views.video_encodings_download, name='video_encodings_download'),
url(r'^group_configurations/{}$'.format(settings.COURSE_KEY_PATTERN), url(r'^group_configurations/{}$'.format(settings.COURSE_KEY_PATTERN),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment