Commit 538a3d78 by Mushtaq Ali Committed by muzaffaryousaf

Add video transcript config model flags - EDUCATOR-1224

parent 2203de4a
...@@ -33,6 +33,7 @@ from edxval.api import ( ...@@ -33,6 +33,7 @@ from edxval.api import (
remove_transcript_preferences, remove_transcript_preferences,
) )
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.waffle_utils import WaffleSwitchNamespace from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace
from contentstore.models import VideoUploadConfig from contentstore.models import VideoUploadConfig
...@@ -129,7 +130,7 @@ class StatusDisplayStrings(object): ...@@ -129,7 +130,7 @@ class StatusDisplayStrings(object):
"invalid_token": _INVALID_TOKEN, "invalid_token": _INVALID_TOKEN,
"imported": _IMPORTED, "imported": _IMPORTED,
"transcription_in_progress": _TRANSCRIPTION_IN_PROGRESS, "transcription_in_progress": _TRANSCRIPTION_IN_PROGRESS,
"transcription_ready": _TRANSCRIPT_READY, "transcript_ready": _TRANSCRIPT_READY,
} }
@staticmethod @staticmethod
...@@ -339,6 +340,11 @@ def transcript_preferences_handler(request, course_key_string): ...@@ -339,6 +340,11 @@ def transcript_preferences_handler(request, course_key_string):
Returns: valid json response or 400 with error message Returns: valid json response or 400 with error message
""" """
course_key = CourseKey.from_string(course_key_string)
is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course_key)
if not is_video_transcript_enabled:
return HttpResponseNotFound()
if request.method == 'POST': if request.method == 'POST':
data = request.json data = request.json
provider = data.get('provider') provider = data.get('provider')
...@@ -550,6 +556,7 @@ def videos_index_html(course): ...@@ -550,6 +556,7 @@ def videos_index_html(course):
""" """
Returns an HTML page to display previous video uploads and allow new ones Returns an HTML page to display previous video uploads and allow new ones
""" """
is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course.id)
context = { context = {
'context_course': course, 'context_course': course,
'image_upload_url': reverse_course_url('video_images_handler', unicode(course.id)), 'image_upload_url': reverse_course_url('video_images_handler', unicode(course.id)),
...@@ -567,19 +574,21 @@ def videos_index_html(course): ...@@ -567,19 +574,21 @@ def videos_index_html(course):
'max_width': settings.VIDEO_IMAGE_MAX_WIDTH, 'max_width': settings.VIDEO_IMAGE_MAX_WIDTH,
'max_height': settings.VIDEO_IMAGE_MAX_HEIGHT, 'max_height': settings.VIDEO_IMAGE_MAX_HEIGHT,
'supported_file_formats': settings.VIDEO_IMAGE_SUPPORTED_FILE_FORMATS 'supported_file_formats': settings.VIDEO_IMAGE_SUPPORTED_FILE_FORMATS
} },
'is_video_transcript_enabled': is_video_transcript_enabled,
'video_transcript_settings': None,
'active_transcript_preferences': None
} }
context.update({ if is_video_transcript_enabled:
'video_transcript_settings': { context['video_transcript_settings'] = {
'transcript_preferences_handler_url': reverse_course_url( 'transcript_preferences_handler_url': reverse_course_url(
'transcript_preferences_handler', 'transcript_preferences_handler',
unicode(course.id) unicode(course.id)
), ),
'transcription_plans': get_3rd_party_transcription_plans(), 'transcription_plans': get_3rd_party_transcription_plans(),
}, }
'active_transcript_preferences': get_transcript_preferences(unicode(course.id)) context['active_transcript_preferences'] = get_transcript_preferences(unicode(course.id))
})
return render_to_response('videos_index.html', context) return render_to_response('videos_index.html', context)
...@@ -662,9 +671,11 @@ def videos_post(course, request): ...@@ -662,9 +671,11 @@ def videos_post(course, request):
('course_key', unicode(course.id)), ('course_key', unicode(course.id)),
] ]
transcript_preferences = get_transcript_preferences(unicode(course.id)) is_video_transcript_enabled = VideoTranscriptEnabledFlag.feature_enabled(course.id)
if transcript_preferences is not None: if is_video_transcript_enabled:
metadata_list.append(('transcript_preferences', json.dumps(transcript_preferences))) transcript_preferences = get_transcript_preferences(unicode(course.id))
if transcript_preferences is not None:
metadata_list.append(('transcript_preferences', json.dumps(transcript_preferences)))
for metadata_name, value in metadata_list: for metadata_name, value in metadata_list:
key.set_metadata(metadata_name, value) key.set_metadata(metadata_name, value)
......
...@@ -16,6 +16,7 @@ define([ ...@@ -16,6 +16,7 @@ define([
videoUploadMaxFileSizeInGB, videoUploadMaxFileSizeInGB,
activeTranscriptPreferences, activeTranscriptPreferences,
videoTranscriptSettings, videoTranscriptSettings,
isVideoTranscriptEnabled,
videoImageSettings videoImageSettings
) { ) {
var activeView = new ActiveVideoUploadListView({ var activeView = new ActiveVideoUploadListView({
...@@ -27,6 +28,7 @@ define([ ...@@ -27,6 +28,7 @@ define([
videoImageSettings: videoImageSettings, videoImageSettings: videoImageSettings,
activeTranscriptPreferences: activeTranscriptPreferences, activeTranscriptPreferences: activeTranscriptPreferences,
videoTranscriptSettings: videoTranscriptSettings, videoTranscriptSettings: videoTranscriptSettings,
isVideoTranscriptEnabled: isVideoTranscriptEnabled,
onFileUploadDone: function(activeVideos) { onFileUploadDone: function(activeVideos) {
$.ajax({ $.ajax({
url: videoHandlerUrl, url: videoHandlerUrl,
......
...@@ -20,6 +20,10 @@ define( ...@@ -20,6 +20,10 @@ define(
fail: 'upload_failed', fail: 'upload_failed',
success: 'upload_completed' success: 'upload_completed'
}, },
videoUploadMaxFileSizeInGB = 5,
videoSupportedFileFormats = ['.mp4', '.mov'],
createActiveUploadListView,
$courseVideoSettingsButton,
makeUploadUrl, makeUploadUrl,
getSentRequests, getSentRequests,
verifyUploadViewInfo, verifyUploadViewInfo,
...@@ -29,6 +33,22 @@ define( ...@@ -29,6 +33,22 @@ define(
verifyA11YMessage, verifyA11YMessage,
verifyUploadPostRequest; verifyUploadPostRequest;
createActiveUploadListView = function(isVideoTranscriptEnabled) {
return new ActiveVideoUploadListView({
concurrentUploadLimit: concurrentUploadLimit,
postUrl: POST_URL,
courseVideoSettingsButton: $courseVideoSettingsButton,
videoSupportedFileFormats: videoSupportedFileFormats,
videoUploadMaxFileSizeInGB: videoUploadMaxFileSizeInGB,
activeTranscriptPreferences: {},
videoTranscriptSettings: {
transcript_preferences_handler_url: '',
transcription_plans: {}
},
isVideoTranscriptEnabled: isVideoTranscriptEnabled
});
};
describe('ActiveVideoUploadListView', function() { describe('ActiveVideoUploadListView', function() {
beforeEach(function() { beforeEach(function() {
setFixtures( setFixtures(
...@@ -40,22 +60,8 @@ define( ...@@ -40,22 +60,8 @@ define(
); );
TemplateHelpers.installTemplate('active-video-upload'); TemplateHelpers.installTemplate('active-video-upload');
TemplateHelpers.installTemplate('active-video-upload-list'); TemplateHelpers.installTemplate('active-video-upload-list');
this.postUrl = POST_URL; $courseVideoSettingsButton = $('.course-video-settings-button');
this.courseVideoSettingsButton = $('.course-video-settings-button'); this.view = createActiveUploadListView(true);
this.videoSupportedFileFormats = ['.mp4', '.mov'];
this.videoUploadMaxFileSizeInGB = 5;
this.view = new ActiveVideoUploadListView({
concurrentUploadLimit: concurrentUploadLimit,
postUrl: this.postUrl,
courseVideoSettingsButton: this.courseVideoSettingsButton,
videoSupportedFileFormats: this.videoSupportedFileFormats,
videoUploadMaxFileSizeInGB: this.videoUploadMaxFileSizeInGB,
activeTranscriptPreferences: {},
videoTranscriptSettings: {
transcript_preferences_handler_url: '',
transcription_plans: {}
}
});
this.view.render(); this.view.render();
jasmine.Ajax.install(); jasmine.Ajax.install();
}); });
...@@ -94,9 +100,15 @@ define( ...@@ -94,9 +100,15 @@ define(
}); });
it('shows course video settings pane when course video settings button is clicked', function() { it('shows course video settings pane when course video settings button is clicked', function() {
expect($('.course-video-settings-container')).not.toExist(); $courseVideoSettingsButton.click();
this.courseVideoSettingsButton.click(); expect(this.view.courseVideoSettingsView).toBeDefined();
expect($('.course-video-settings-container')).toExist(); expect(this.view.courseVideoSettingsView.$el.find('.course-video-settings-container')).toExist();
});
it('should not initiate course video settings view when video transcript is disabled', function() {
this.view = createActiveUploadListView(false);
$courseVideoSettingsButton.click();
expect(this.view.courseVideoSettingsView).toBeUndefined();
}); });
it('should not show a notification message if there are no active video uploads', function() { it('should not show a notification message if there are no active video uploads', function() {
...@@ -328,7 +340,7 @@ define( ...@@ -328,7 +340,7 @@ define(
'Your file could not be uploaded', 'Your file could not be uploaded',
StringUtils.interpolate( StringUtils.interpolate(
'{fileName} is not in a supported file format. Supported file formats are {supportedFormats}.', // eslint-disable-line max-len '{fileName} is not in a supported file format. Supported file formats are {supportedFormats}.', // eslint-disable-line max-len
{fileName: files[index].name, supportedFormats: self.videoSupportedFileFormats.join(' and ')} // eslint-disable-line max-len {fileName: files[index].name, supportedFormats: videoSupportedFileFormats.join(' and ')} // eslint-disable-line max-len
) )
); );
}); });
...@@ -361,7 +373,7 @@ define( ...@@ -361,7 +373,7 @@ define(
verifyUploadViewInfo( verifyUploadViewInfo(
uploadView, uploadView,
'Your file could not be uploaded', 'Your file could not be uploaded',
'file.mp4 exceeds maximum size of ' + this.videoUploadMaxFileSizeInGB + ' GB.' 'file.mp4 exceeds maximum size of ' + videoUploadMaxFileSizeInGB + ' GB.'
); );
verifyA11YMessage( verifyA11YMessage(
StringUtils.interpolate( StringUtils.interpolate(
...@@ -431,7 +443,7 @@ define( ...@@ -431,7 +443,7 @@ define(
expect(jasmine.Ajax.requests.count()).toEqual(caseInfo.numFiles); expect(jasmine.Ajax.requests.count()).toEqual(caseInfo.numFiles);
_.each(_.range(caseInfo.numFiles), function(index) { _.each(_.range(caseInfo.numFiles), function(index) {
request = jasmine.Ajax.requests.at(index); request = jasmine.Ajax.requests.at(index);
expect(request.url).toEqual(self.postUrl); expect(request.url).toEqual(POST_URL);
expect(request.method).toEqual('POST'); expect(request.method).toEqual('POST');
expect(request.requestHeaders['Content-Type']).toEqual('application/json'); expect(request.requestHeaders['Content-Type']).toEqual('application/json');
expect(request.requestHeaders.Accept).toContain('application/json'); expect(request.requestHeaders.Accept).toContain('application/json');
......
...@@ -43,6 +43,7 @@ define([ ...@@ -43,6 +43,7 @@ define([
this.postUrl = options.postUrl; this.postUrl = options.postUrl;
this.activeTranscriptPreferences = options.activeTranscriptPreferences; this.activeTranscriptPreferences = options.activeTranscriptPreferences;
this.videoTranscriptSettings = options.videoTranscriptSettings; this.videoTranscriptSettings = options.videoTranscriptSettings;
this.isVideoTranscriptEnabled = options.isVideoTranscriptEnabled;
this.videoSupportedFileFormats = options.videoSupportedFileFormats; this.videoSupportedFileFormats = options.videoSupportedFileFormats;
this.videoUploadMaxFileSizeInGB = options.videoUploadMaxFileSizeInGB; this.videoUploadMaxFileSizeInGB = options.videoUploadMaxFileSizeInGB;
this.onFileUploadDone = options.onFileUploadDone; this.onFileUploadDone = options.onFileUploadDone;
...@@ -62,16 +63,18 @@ define([ ...@@ -62,16 +63,18 @@ define([
supportedVideoTypes: this.videoSupportedFileFormats.join(', ') supportedVideoTypes: this.videoSupportedFileFormats.join(', ')
} }
); );
this.listenTo( if (this.isVideoTranscriptEnabled) {
Backbone, this.listenTo(
'coursevideosettings:syncActiveTranscriptPreferences', Backbone,
this.syncActiveTranscriptPreferences 'coursevideosettings:syncActiveTranscriptPreferences',
); this.syncActiveTranscriptPreferences
this.listenTo( );
Backbone, this.listenTo(
'coursevideosettings:destroyCourseVideoSettingsView', Backbone,
this.destroyCourseVideoSettingsView 'coursevideosettings:destroyCourseVideoSettingsView',
); this.destroyCourseVideoSettingsView
);
}
}, },
syncActiveTranscriptPreferences: function(activeTranscriptPreferences) { syncActiveTranscriptPreferences: function(activeTranscriptPreferences) {
...@@ -79,12 +82,14 @@ define([ ...@@ -79,12 +82,14 @@ define([
}, },
showCourseVideoSettingsView: function(event) { showCourseVideoSettingsView: function(event) {
this.courseVideoSettingsView = new CourseVideoSettingsView({ if (this.isVideoTranscriptEnabled) {
activeTranscriptPreferences: this.activeTranscriptPreferences, this.courseVideoSettingsView = new CourseVideoSettingsView({
videoTranscriptSettings: this.videoTranscriptSettings activeTranscriptPreferences: this.activeTranscriptPreferences,
}); videoTranscriptSettings: this.videoTranscriptSettings
this.courseVideoSettingsView.render(); });
event.stopPropagation(); this.courseVideoSettingsView.render();
event.stopPropagation();
}
}, },
destroyCourseVideoSettingsView: function() { destroyCourseVideoSettingsView: function() {
......
...@@ -337,6 +337,22 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -337,6 +337,22 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett
}, },
updateSuccessResponseStatus: function(data) { updateSuccessResponseStatus: function(data) {
var dateModified = data ? moment.utc(data.modified).format('ll') : '';
// Update last modified date
if (dateModified) {
HtmlUtils.setHtml(
this.$el.find('.last-updated-text'),
HtmlUtils.interpolateHtml(
HtmlUtils.HTML('{lastUpdateText} {dateModified}'),
{
lastUpdateText: gettext('Last updated'),
dateModified: dateModified
}
)
);
}
this.renderResponseStatus(gettext('Settings updated'), 'success'); this.renderResponseStatus(gettext('Settings updated'), 'success');
// Sync ActiveUploadListView with latest active plan. // Sync ActiveUploadListView with latest active plan.
this.activeTranscriptionPlan = data; this.activeTranscriptionPlan = data;
...@@ -533,6 +549,8 @@ function($, Backbone, _, gettext, moment, HtmlUtils, StringUtils, TranscriptSett ...@@ -533,6 +549,8 @@ 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.
// Trigger destroy transcript event. // Trigger destroy transcript event.
Backbone.trigger('coursevideosettings:destroyCourseVideoSettingsView'); Backbone.trigger('coursevideosettings:destroyCourseVideoSettingsView');
......
...@@ -45,9 +45,11 @@ ...@@ -45,9 +45,11 @@
<%- gettext('Update Settings') %> <%- gettext('Update Settings') %>
<span id='update-button-text' class='sr'><%-gettext('Press update settings to update course video settings') %></span> <span id='update-button-text' class='sr'><%-gettext('Press update settings to update course video settings') %></span>
</button> </button>
<span class='last-updated-text'>
<%if (dateModified) { %> <%if (dateModified) { %>
<span class='last-updated-text'><%- gettext('Last updated')%> <%- dateModified %></span> <%- gettext('Last updated')%> <%- dateModified %>
<% } %> <% } %>
</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
${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},
${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},
${video_image_settings | n, dump_js_escaped_json} ${video_image_settings | n, dump_js_escaped_json}
); );
}); });
...@@ -55,12 +56,14 @@ ...@@ -55,12 +56,14 @@
<span class="sr">&gt; </span>${_("Video Uploads")} <span class="sr">&gt; </span>${_("Video Uploads")}
</h1> </h1>
% if is_video_transcript_enabled :
<nav class="nav-actions" aria-label="${_('Page Actions')}"> <nav class="nav-actions" aria-label="${_('Page Actions')}">
<h3 class="sr">${_("Page Actions")}</h3> <h3 class="sr">${_("Page Actions")}</h3>
<div class="nav-item"> <div class="nav-item">
<button class="button course-video-settings-button"><span class="icon fa fa-cog" aria-hidden="true"></span> ${_("Course Video Settings")}</button> <button class="button course-video-settings-button"><span class="icon fa fa-cog" aria-hidden="true"></span> ${_("Course Video Settings")}</button>
</div> </div>
</nav> </nav>
% endif
</header> </header>
</div> </div>
......
...@@ -5,16 +5,24 @@ Django admin dashboard configuration for Video XModule. ...@@ -5,16 +5,24 @@ Django admin dashboard configuration for Video XModule.
from config_models.admin import ConfigurationModelAdmin, KeyedConfigurationModelAdmin from config_models.admin import ConfigurationModelAdmin, KeyedConfigurationModelAdmin
from django.contrib import admin from django.contrib import admin
from openedx.core.djangoapps.video_config.forms import CourseHLSPlaybackFlagAdminForm from openedx.core.djangoapps.video_config.forms import (
from openedx.core.djangoapps.video_config.models import CourseHLSPlaybackEnabledFlag, HLSPlaybackEnabledFlag CourseHLSPlaybackFlagAdminForm, CourseVideoTranscriptFlagAdminForm
)
from openedx.core.djangoapps.video_config.models import (
CourseHLSPlaybackEnabledFlag, HLSPlaybackEnabledFlag,
CourseVideoTranscriptEnabledFlag, VideoTranscriptEnabledFlag
)
class CourseHLSPlaybackEnabledFlagAdmin(KeyedConfigurationModelAdmin): class CourseSpecificEnabledFlagBaseAdmin(KeyedConfigurationModelAdmin):
""" """
Admin of HLS Playback feature on course-by-course basis. Admin of course specific feature on course-by-course basis.
Allows searching by course id. Allows searching by course id.
""" """
form = CourseHLSPlaybackFlagAdminForm # Make abstract base class
class Meta(object):
abstract = True
search_fields = ['course_id'] search_fields = ['course_id']
fieldsets = ( fieldsets = (
(None, { (None, {
...@@ -23,5 +31,23 @@ class CourseHLSPlaybackEnabledFlagAdmin(KeyedConfigurationModelAdmin): ...@@ -23,5 +31,23 @@ class CourseHLSPlaybackEnabledFlagAdmin(KeyedConfigurationModelAdmin):
}), }),
) )
class CourseHLSPlaybackEnabledFlagAdmin(CourseSpecificEnabledFlagBaseAdmin):
"""
Admin of HLS Playback feature on course-by-course basis.
Allows searching by course id.
"""
form = CourseHLSPlaybackFlagAdminForm
class CourseVideoTranscriptEnabledFlagAdmin(CourseSpecificEnabledFlagBaseAdmin):
"""
Admin of Video Transcript feature on course-by-course basis.
Allows searching by course id.
"""
form = CourseHLSPlaybackFlagAdminForm
admin.site.register(HLSPlaybackEnabledFlag, ConfigurationModelAdmin) admin.site.register(HLSPlaybackEnabledFlag, ConfigurationModelAdmin)
admin.site.register(CourseHLSPlaybackEnabledFlag, CourseHLSPlaybackEnabledFlagAdmin) admin.site.register(CourseHLSPlaybackEnabledFlag, CourseHLSPlaybackEnabledFlagAdmin)
admin.site.register(VideoTranscriptEnabledFlag, ConfigurationModelAdmin)
admin.site.register(CourseVideoTranscriptEnabledFlag, CourseHLSPlaybackEnabledFlagAdmin)
...@@ -7,20 +7,20 @@ from django import forms ...@@ -7,20 +7,20 @@ from django import forms
from opaque_keys import InvalidKeyError from opaque_keys import InvalidKeyError
from opaque_keys.edx.locator import CourseLocator from opaque_keys.edx.locator import CourseLocator
from openedx.core.djangoapps.video_config.models import CourseHLSPlaybackEnabledFlag from openedx.core.djangoapps.video_config.models import CourseHLSPlaybackEnabledFlag, CourseVideoTranscriptEnabledFlag
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class CourseHLSPlaybackFlagAdminForm(forms.ModelForm): class CourseSpecificFlagAdminBaseForm(forms.ModelForm):
""" """
Form for course-specific HLS Playback configuration. Form for course-specific feature configuration.
""" """
# Make abstract base class
class Meta(object): class Meta(object):
model = CourseHLSPlaybackEnabledFlag abstract = True
fields = '__all__'
def clean_course_id(self): def clean_course_id(self):
""" """
...@@ -42,3 +42,23 @@ class CourseHLSPlaybackFlagAdminForm(forms.ModelForm): ...@@ -42,3 +42,23 @@ class CourseHLSPlaybackFlagAdminForm(forms.ModelForm):
raise forms.ValidationError(msg) raise forms.ValidationError(msg)
return course_key return course_key
class CourseHLSPlaybackFlagAdminForm(CourseSpecificFlagAdminBaseForm):
"""
Form for course-specific HLS Playback configuration.
"""
class Meta(object):
model = CourseHLSPlaybackEnabledFlag
fields = '__all__'
class CourseVideoTranscriptFlagAdminForm(CourseSpecificFlagAdminBaseForm):
"""
Form for course-specific Video Transcript configuration.
"""
class Meta(object):
model = CourseVideoTranscriptEnabledFlag
fields = '__all__'
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import django.db.models.deletion
import openedx.core.djangoapps.xmodule_django.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('video_config', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='CourseVideoTranscriptEnabledFlag',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
('course_id', openedx.core.djangoapps.xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
],
options={
'ordering': ('-change_date',),
'abstract': False,
},
),
migrations.CreateModel(
name='VideoTranscriptEnabledFlag',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
('enabled_for_all_courses', models.BooleanField(default=False)),
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
],
options={
'ordering': ('-change_date',),
'abstract': False,
},
),
]
...@@ -66,3 +66,68 @@ class CourseHLSPlaybackEnabledFlag(ConfigurationModel): ...@@ -66,3 +66,68 @@ class CourseHLSPlaybackEnabledFlag(ConfigurationModel):
course_key=unicode(self.course_id), course_key=unicode(self.course_id),
not_enabled=not_en not_enabled=not_en
) )
class VideoTranscriptEnabledFlag(ConfigurationModel):
"""
Enables Video Transcript across the platform.
When this feature flag is set to true, individual courses
must also have Video Transcript enabled for this feature to
take effect.
When this feature is enabled, 3rd party transcript integration functionality would be available accross all
courses or some specific courses and S3 video transcript would be served (currently as a fallback).
"""
# this field overrides course-specific settings
enabled_for_all_courses = BooleanField(default=False)
@classmethod
def feature_enabled(cls, course_id):
"""
Looks at the currently active configuration model to determine whether
the Video Transcript feature is available.
If the feature flag is not enabled, the feature is not available.
If the flag is enabled for all the courses, feature is available.
If the flag is enabled and the provided course_id is for an course
with Video Transcript enabled, the feature is available.
Arguments:
course_id (CourseKey): course id for whom feature will be checked.
"""
if not VideoTranscriptEnabledFlag.is_enabled():
return False
elif not VideoTranscriptEnabledFlag.current().enabled_for_all_courses:
feature = (CourseVideoTranscriptEnabledFlag.objects
.filter(course_id=course_id)
.order_by('-change_date')
.first())
return feature.enabled if feature else False
return True
def __unicode__(self):
current_model = VideoTranscriptEnabledFlag.current()
return u"VideoTranscriptEnabledFlag: enabled {is_enabled}".format(
is_enabled=current_model.is_enabled()
)
class CourseVideoTranscriptEnabledFlag(ConfigurationModel):
"""
Enables Video Transcript for a specific course. Global feature must be
enabled for this to take effect.
When this feature is enabled, 3rd party transcript integration functionality would be available for the
specific course and S3 video transcript would be served (currently as a fallback).
"""
KEY_FIELDS = ('course_id',)
course_id = CourseKeyField(max_length=255, db_index=True)
def __unicode__(self):
not_en = "Not "
if self.enabled:
not_en = ""
return u"Course '{course_key}': Video Transcript {not_enabled}Enabled".format(
course_key=unicode(self.course_id),
not_enabled=not_en
)
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