Merge pull request #12822 from edx/patch/2016-06-22
Patch Release 2016-06-22
This commit is contained in:
@@ -9,21 +9,22 @@ import ddt
|
||||
import freezegun
|
||||
from mock import patch
|
||||
from nose.plugins.attrib import attr
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from lms.djangoapps.commerce.tests import test_utils as ecomm_test_utils
|
||||
from openedx.core.djangoapps.theming.tests import test_util as theming_test_utils
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
|
||||
from util.testing import UrlResetMixin
|
||||
from embargo.test_utils import restrict_course
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from student.models import CourseEnrollment
|
||||
import lms.djangoapps.commerce.tests.test_utils as ecomm_test_utils
|
||||
|
||||
from course_modes.models import CourseMode, Mode
|
||||
from openedx.core.djangoapps.theming.test_util import with_is_edx_domain
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from embargo.test_utils import restrict_course
|
||||
from student.models import CourseEnrollment
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from util.testing import UrlResetMixin
|
||||
|
||||
|
||||
@attr('shard_3')
|
||||
@@ -373,7 +374,7 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase):
|
||||
self.assertEquals(course_modes, expected_modes)
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@with_is_edx_domain(True)
|
||||
@theming_test_utils.with_is_edx_domain(True)
|
||||
def test_hide_nav(self):
|
||||
# Create the course modes
|
||||
for mode in ["honor", "verified"]:
|
||||
|
||||
@@ -58,7 +58,7 @@ class PasswordResetFormNoActive(PasswordResetForm):
|
||||
email_template_name='registration/password_reset_email.html',
|
||||
use_https=False,
|
||||
token_generator=default_token_generator,
|
||||
from_email=theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL),
|
||||
from_email=theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL),
|
||||
request=None
|
||||
):
|
||||
"""
|
||||
|
||||
@@ -20,7 +20,7 @@ from django.conf import settings
|
||||
from edxmako.shortcuts import render_to_string
|
||||
from util.request import safe_get_host
|
||||
from util.testing import EventTestMixin
|
||||
from openedx.core.djangoapps.theming.test_util import with_is_edx_domain
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_is_edx_domain
|
||||
from openedx.core.djangoapps.theming import helpers as theming_helpers
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class EmailTestMixin(object):
|
||||
email_user.assert_called_with(
|
||||
mock_render_to_string(subject_template, subject_context),
|
||||
mock_render_to_string(body_template, body_context),
|
||||
theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL)
|
||||
theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)
|
||||
)
|
||||
|
||||
def append_allowed_hosts(self, hostname):
|
||||
@@ -298,7 +298,7 @@ class EmailChangeRequestTests(EventTestMixin, TestCase):
|
||||
send_mail.assert_called_with(
|
||||
mock_render_to_string('emails/email_change_subject.txt', context),
|
||||
mock_render_to_string('emails/email_change.txt', context),
|
||||
theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL),
|
||||
theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL),
|
||||
[new_email]
|
||||
)
|
||||
self.assert_event_emitted(
|
||||
|
||||
@@ -125,7 +125,7 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase):
|
||||
(subject, msg, from_addr, to_addrs) = send_email.call_args[0]
|
||||
self.assertIn("Password reset", subject)
|
||||
self.assertIn("You're receiving this e-mail because you requested a password reset", msg)
|
||||
self.assertEquals(from_addr, theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL))
|
||||
self.assertEquals(from_addr, theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL))
|
||||
self.assertEquals(len(to_addrs), 1)
|
||||
self.assertIn(self.user.email, to_addrs)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ from certificates.tests.factories import GeneratedCertificateFactory # pylint:
|
||||
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
|
||||
import shoppingcart # pylint: disable=import-error
|
||||
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin
|
||||
from openedx.core.djangoapps.theming.test_util import with_is_edx_domain
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_is_edx_domain
|
||||
|
||||
# Explicitly import the cache from ConfigurationModel so we can reset it after each test
|
||||
from config_models.models import cache
|
||||
|
||||
@@ -2229,11 +2229,11 @@ def reactivation_email_for_user(user):
|
||||
message = render_to_string('emails/activation_email.txt', context)
|
||||
|
||||
try:
|
||||
user.email_user(subject, message, theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL))
|
||||
user.email_user(subject, message, theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL))
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.error(
|
||||
u'Unable to send reactivation email from "%s"',
|
||||
theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL),
|
||||
theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL),
|
||||
exc_info=True
|
||||
)
|
||||
return JsonResponse({
|
||||
@@ -2357,7 +2357,7 @@ def confirm_email_change(request, key): # pylint: disable=unused-argument
|
||||
user.email_user(
|
||||
subject,
|
||||
message,
|
||||
theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL)
|
||||
theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)
|
||||
)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.warning('Unable to send confirmation email to old address', exc_info=True)
|
||||
@@ -2373,7 +2373,7 @@ def confirm_email_change(request, key): # pylint: disable=unused-argument
|
||||
user.email_user(
|
||||
subject,
|
||||
message,
|
||||
theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL)
|
||||
theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)
|
||||
)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.warning('Unable to send confirmation email to new address', exc_info=True)
|
||||
|
||||
@@ -535,8 +535,6 @@
|
||||
|
||||
.speed-option,
|
||||
.control-lang {
|
||||
@include border-left($baseline/10 solid rgb(14, 166, 236));
|
||||
font-weight: $font-bold;
|
||||
color: rgb(14, 166, 236); // UXPL primary accent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +55,8 @@
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
<div class="subtitles">
|
||||
<ol class="subtitles-menu"><li></li></ol>
|
||||
</div>
|
||||
|
||||
<ol class="subtitles"><li></li></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -109,9 +108,7 @@
|
||||
</section>
|
||||
</article>
|
||||
|
||||
<div class="subtitles">
|
||||
<ol class="subtitles-menu"><li></li></ol>
|
||||
</div>
|
||||
<ol class="subtitles"><li></li></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,12 @@ var options = {
|
||||
libraryFilesToInclude: [
|
||||
{pattern: 'common_static/js/vendor/requirejs/require.js', included: true},
|
||||
{pattern: 'RequireJS-namespace-undefine.js', included: true},
|
||||
{pattern: 'spec/main_requirejs.js', included: true},
|
||||
|
||||
{pattern: 'common_static/coffee/src/ajax_prefix.js', included: true},
|
||||
{pattern: 'common_static/common/js/vendor/underscore.js', included: true},
|
||||
{pattern: 'common_static/common/js/vendor/backbone.js', included: true},
|
||||
{pattern: 'common_static/edx-ui-toolkit/js/utils/global-loader.js', included: true},
|
||||
{pattern: 'common_static/js/vendor/CodeMirror/codemirror.js', included: true},
|
||||
{pattern: 'common_static/js/vendor/draggabilly.js'},
|
||||
{pattern: 'common_static/common/js/vendor/jquery.js', included: true},
|
||||
@@ -48,14 +50,11 @@ var options = {
|
||||
{pattern: 'common_static/js/vendor/jasmine-imagediff.js', included: true},
|
||||
{pattern: 'common_static/common/js/spec_helpers/jasmine-waituntil.js', included: true},
|
||||
{pattern: 'common_static/common/js/spec_helpers/jasmine-extensions.js', included: true},
|
||||
{pattern: 'common_static/js/vendor/sinon-1.17.0.js', included: true},
|
||||
|
||||
{pattern: 'spec/main_requirejs.js', included: true},
|
||||
{pattern: 'common_static/js/vendor/sinon-1.17.0.js', included: true}
|
||||
],
|
||||
|
||||
libraryFiles: [
|
||||
{pattern: 'common_static/edx-pattern-library/js/**/*.js'},
|
||||
{pattern: 'common_static/edx-ui-toolkit/js/**/*.js'}
|
||||
{pattern: 'common_static/edx-pattern-library/js/**/*.js'}
|
||||
],
|
||||
|
||||
// Make sure the patterns in sourceFiles and specFiles do not match the same file.
|
||||
|
||||
@@ -1,36 +1,4 @@
|
||||
(function(requirejs, define) {
|
||||
'use strict';
|
||||
// We do not wish to bundle common libraries (that may also be used by non-RequireJS code on the page
|
||||
// into the optimized files. Therefore load these libraries through script tags and explicitly define them.
|
||||
// Note that when the optimizer executes this code, window will not be defined.
|
||||
if (window) {
|
||||
var defineDependency = function (globalName, name, noShim) {
|
||||
var getGlobalValue = function(name) {
|
||||
var globalNamePath = name.split('.'),
|
||||
result = window,
|
||||
i;
|
||||
for (i = 0; i < globalNamePath.length; i++) {
|
||||
result = result[globalNamePath[i]];
|
||||
}
|
||||
return result;
|
||||
},
|
||||
globalValue = getGlobalValue(globalName);
|
||||
if (globalValue) {
|
||||
if (noShim) {
|
||||
define(name, {});
|
||||
}
|
||||
else {
|
||||
define(name, [], function() { return globalValue; });
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error("Expected library to be included on page, but not found on window object: " + name);
|
||||
}
|
||||
};
|
||||
defineDependency("jQuery", "jquery");
|
||||
defineDependency("jQuery", "jquery-migrate");
|
||||
defineDependency("_", "underscore");
|
||||
}
|
||||
(function(requirejs) {
|
||||
requirejs.config({
|
||||
baseUrl: '/base/',
|
||||
paths: {
|
||||
@@ -38,8 +6,7 @@
|
||||
"modernizr": "common_static/edx-pattern-library/js/modernizr-custom",
|
||||
"afontgarde": "common_static/edx-pattern-library/js/afontgarde",
|
||||
"edxicons": "common_static/edx-pattern-library/js/edx-icons",
|
||||
"draggabilly": "common_static/js/vendor/draggabilly",
|
||||
'edx-ui-toolkit': 'common_static/edx-ui-toolkit'
|
||||
"draggabilly": "common_static/js/vendor/draggabilly"
|
||||
},
|
||||
"moment": {
|
||||
exports: "moment"
|
||||
@@ -51,4 +18,5 @@
|
||||
exports: "AFontGarde"
|
||||
}
|
||||
});
|
||||
}).call(this, RequireJS.requirejs, RequireJS.define);
|
||||
|
||||
}).call(this, RequireJS.requirejs);
|
||||
|
||||
@@ -266,7 +266,6 @@
|
||||
expect($('.closed-captions')).toHaveAttrs({
|
||||
'lang': 'de'
|
||||
});
|
||||
expect(link).toHaveAttr('aria-pressed', 'true');
|
||||
});
|
||||
|
||||
it('when clicking on link with current language', function () {
|
||||
@@ -285,7 +284,6 @@
|
||||
expect(state.storage.setItem)
|
||||
.not.toHaveBeenCalledWith('language', 'en');
|
||||
expect($('.langs-list li.is-active').length).toBe(1);
|
||||
expect(link).toHaveAttr('aria-pressed', 'true');
|
||||
});
|
||||
|
||||
it('open the language toggle on hover', function () {
|
||||
@@ -415,7 +413,7 @@
|
||||
});
|
||||
|
||||
it('show explanation message', function () {
|
||||
expect($('.subtitles .subtitles-menu li')).toHaveText(
|
||||
expect($('.subtitles-menu li')).toHaveText(
|
||||
'Transcript will be displayed when you start playing the video.'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -203,18 +203,16 @@
|
||||
describe('onSpeedChange', function () {
|
||||
beforeEach(function () {
|
||||
state = jasmine.initializePlayer();
|
||||
$('li[data-speed="1.0"]').addClass('is-active').attr('aria-pressed', 'true');
|
||||
$('li[data-speed="1.0"]').addClass('is-active');
|
||||
state.videoSpeedControl.setSpeed(0.75);
|
||||
});
|
||||
|
||||
it('set the new speed as active', function () {
|
||||
expect($('li[data-speed="1.0"]')).not.toHaveClass('is-active');
|
||||
expect($('li[data-speed="1.0"] .speed-option').attr('aria-pressed')).not.toEqual('true');
|
||||
|
||||
expect($('li[data-speed="0.75"]')).toHaveClass('is-active');
|
||||
expect($('li[data-speed="0.75"] .speed-option').attr('aria-pressed')).toEqual('true');
|
||||
|
||||
expect($('.speeds .speed-button .value')).toHaveHtml('0.75x');
|
||||
expect($('.video-speeds li[data-speed="1.0"]'))
|
||||
.not.toHaveClass('is-active');
|
||||
expect($('.video-speeds li[data-speed="0.75"]'))
|
||||
.toHaveClass('is-active');
|
||||
expect($('.speeds .value')).toHaveHtml('0.75x');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
(function (requirejs, require, define) {
|
||||
"use strict";
|
||||
define(
|
||||
'video/08_video_speed_control.js', [
|
||||
'video/00_iterator.js',
|
||||
'edx-ui-toolkit/js/utils/html-utils'
|
||||
], function (Iterator, HtmlUtils) {
|
||||
'video/08_video_speed_control.js',
|
||||
['video/00_iterator.js'],
|
||||
function (Iterator) {
|
||||
/**
|
||||
* Video speed control module.
|
||||
* @exports video/08_video_speed_control.js
|
||||
@@ -96,37 +95,23 @@ define(
|
||||
* Creates any necessary DOM elements, attach them, and set their,
|
||||
* initial configuration.
|
||||
* @param {array} speeds List of speeds available for the player.
|
||||
* @param {string} currentSpeed The current speed set to the player.
|
||||
*/
|
||||
render: function (speeds, currentSpeed) {
|
||||
render: function (speeds) {
|
||||
var speedsContainer = this.speedsContainer,
|
||||
reversedSpeeds = speeds.concat().reverse(),
|
||||
speedsList = $.map(reversedSpeeds, function (speed) {
|
||||
return HtmlUtils.interpolateHtml(
|
||||
HtmlUtils.joinHtml(
|
||||
HtmlUtils.HTML('<li data-speed="{speed}">'),
|
||||
HtmlUtils.HTML('<button class="control speed-option" tabindex="-1" aria-pressed="false">'),
|
||||
HtmlUtils.HTML(speed),
|
||||
HtmlUtils.HTML('x'),
|
||||
HtmlUtils.HTML('</button>'),
|
||||
HtmlUtils.HTML('</li>')
|
||||
),
|
||||
{
|
||||
speed: speed
|
||||
}
|
||||
).toString();
|
||||
return [
|
||||
'<li data-speed="', speed, '">',
|
||||
'<button class="control speed-option" tabindex="-1">',
|
||||
speed, 'x',
|
||||
'</button>',
|
||||
'</li>'
|
||||
].join('');
|
||||
});
|
||||
|
||||
HtmlUtils.setHtml(
|
||||
speedsContainer,
|
||||
HtmlUtils.HTML(speedsList)
|
||||
);
|
||||
speedsContainer.html(speedsList.join(''));
|
||||
this.speedLinks = new Iterator(speedsContainer.find('.speed-option'));
|
||||
HtmlUtils.prepend(
|
||||
this.state.el.find('.secondary-controls'),
|
||||
HtmlUtils.HTML(this.el)
|
||||
);
|
||||
this.setActiveSpeed(currentSpeed);
|
||||
this.state.el.find('.secondary-controls').prepend(this.el);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -231,38 +216,17 @@ define(
|
||||
if (speed !== this.currentSpeed || forceUpdate) {
|
||||
this.speedsContainer
|
||||
.find('li')
|
||||
.siblings("li[data-speed='" + speed + "']");
|
||||
.removeClass('is-active')
|
||||
.siblings("li[data-speed='" + speed + "']")
|
||||
.addClass('is-active');
|
||||
|
||||
this.speedButton.find('.value').text(speed + 'x');
|
||||
this.speedButton.find('.value').html(speed + 'x');
|
||||
this.currentSpeed = speed;
|
||||
|
||||
if (!silent) {
|
||||
this.el.trigger('speedchange', [speed, this.state.speed]);
|
||||
}
|
||||
}
|
||||
|
||||
this.resetActiveSpeed();
|
||||
this.setActiveSpeed(speed);
|
||||
},
|
||||
|
||||
resetActiveSpeed: function() {
|
||||
var speedOptions = this.speedsContainer.find('li');
|
||||
|
||||
$(speedOptions).each(function(index, el) {
|
||||
$(el).removeClass('is-active')
|
||||
.find('.speed-option')
|
||||
.attr('aria-pressed', 'false');
|
||||
});
|
||||
},
|
||||
|
||||
setActiveSpeed: function(speed) {
|
||||
var speedOption = this.speedsContainer.find('li[data-speed="' + speed + '"]');
|
||||
|
||||
speedOption.addClass('is-active')
|
||||
.find('.speed-option')
|
||||
.attr('aria-pressed', 'true');
|
||||
|
||||
this.speedButton.attr('title', gettext('Video speed: ') + speed + 'x');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -280,13 +244,10 @@ define(
|
||||
* @param {jquery Event} event
|
||||
*/
|
||||
clickLinkHandler: function (event) {
|
||||
var el = $(event.currentTarget).parent(),
|
||||
speed = $(el).data('speed');
|
||||
|
||||
this.resetActiveSpeed();
|
||||
this.setActiveSpeed(speed);
|
||||
var speed = $(event.currentTarget).parent().data('speed');
|
||||
|
||||
this.closeMenu();
|
||||
this.state.videoCommands.execute('speed', speed);
|
||||
this.closeMenu(true);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
define('video/09_video_caption.js',[
|
||||
'video/00_sjson.js',
|
||||
'video/00_async_process.js',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'draggabilly',
|
||||
'modernizr',
|
||||
'afontgarde',
|
||||
'edxicons'
|
||||
], function (Sjson, AsyncProcess, HtmlUtils, Draggabilly) {
|
||||
], function (Sjson, AsyncProcess, Draggabilly) {
|
||||
|
||||
/**
|
||||
* @desc VideoCaption module exports a function.
|
||||
@@ -81,53 +80,47 @@
|
||||
renderElements: function () {
|
||||
var languages = this.state.config.transcriptLanguages;
|
||||
|
||||
var langHtml = HtmlUtils.joinHtml(
|
||||
HtmlUtils.HTML('<div class="grouped-controls">'),
|
||||
HtmlUtils.HTML('<button class="control toggle-captions" aria-disabled="false">'),
|
||||
HtmlUtils.HTML('<span class="icon-fallback-img">'),
|
||||
HtmlUtils.HTML('<span class="icon fa fa-cc" aria-hidden="true"></span>'),
|
||||
HtmlUtils.HTML('<span class="sr control-text"></span>'),
|
||||
HtmlUtils.HTML('</span>'),
|
||||
HtmlUtils.HTML('</button>'),
|
||||
HtmlUtils.HTML('<button class="control toggle-transcript" aria-disabled="false">'),
|
||||
HtmlUtils.HTML('<span class="icon-fallback-img">'),
|
||||
HtmlUtils.HTML('<span class="icon fa fa-quote-left" aria-hidden="true"></span>'),
|
||||
HtmlUtils.HTML('<span class="sr control-text"></span>'),
|
||||
HtmlUtils.HTML('</span>'),
|
||||
HtmlUtils.HTML('</button>'),
|
||||
HtmlUtils.HTML('<div class="lang menu-container" role="application">'),
|
||||
HtmlUtils.HTML('<p class="sr instructions" id="lang-instructions"></p>'),
|
||||
HtmlUtils.HTML('<button class="control language-menu" aria-disabled="false"'),
|
||||
HtmlUtils.HTML('aria-describedby="lang-instructions" '),
|
||||
HtmlUtils.HTML('title="'),
|
||||
var langTemplate = [
|
||||
'<div class="grouped-controls">',
|
||||
'<button class="control toggle-captions" aria-disabled="false">',
|
||||
'<span class="icon-fallback-img">',
|
||||
'<span class="icon fa fa-cc" aria-hidden="true"></span>',
|
||||
'<span class="sr control-text"></span>',
|
||||
'</span>',
|
||||
'</button>',
|
||||
'<button class="control toggle-transcript" aria-disabled="false">',
|
||||
'<span class="icon-fallback-img">',
|
||||
'<span class="icon fa fa-quote-left" aria-hidden="true"></span>',
|
||||
'<span class="sr control-text"></span>',
|
||||
'</span>',
|
||||
'</button>',
|
||||
'<div class="lang menu-container" role="application">',
|
||||
'<p class="sr instructions" id="lang-instructions"></p>',
|
||||
'<button class="control language-menu" aria-disabled="false"',
|
||||
'aria-describedby="lang-instructions" ',
|
||||
'title="',
|
||||
gettext('Open language menu'),
|
||||
HtmlUtils.HTML('">'),
|
||||
HtmlUtils.HTML('<span class="icon-fallback-img">'),
|
||||
HtmlUtils.HTML('<span class="icon fa fa-caret-left" aria-hidden="true"></span>'),
|
||||
HtmlUtils.HTML('<span class="sr control-text"></span>'),
|
||||
HtmlUtils.HTML('</span>'),
|
||||
HtmlUtils.HTML('</button>'),
|
||||
HtmlUtils.HTML('</div>'),
|
||||
HtmlUtils.HTML('</div>)')
|
||||
);
|
||||
'">',
|
||||
'<span class="icon-fallback-img">',
|
||||
'<span class="icon fa fa-caret-left" aria-hidden="true"></span>',
|
||||
'<span class="sr control-text"></span>',
|
||||
'</span>',
|
||||
'</button>',
|
||||
'</div>',
|
||||
'</div>'
|
||||
].join('');
|
||||
|
||||
var subtitlesHtml = HtmlUtils.interpolateHtml(
|
||||
HtmlUtils.joinHtml(
|
||||
HtmlUtils.HTML('<div class="subtitles" role="region" id="transcript-{courseId}">'),
|
||||
HtmlUtils.HTML('<h3 id="transcript-label-{courseId}" class="transcript-title sr"></h3>'),
|
||||
HtmlUtils.HTML('<ol id="transcript-captions" class="subtitles-menu" lang="{courseLang}"></ol>'),
|
||||
HtmlUtils.HTML('</div>')
|
||||
),
|
||||
{
|
||||
courseId: this.state.id,
|
||||
courseLang: this.state.lang
|
||||
}
|
||||
);
|
||||
var template = [
|
||||
'<div class="subtitles" role="region" id="transcript-' + this.state.id + '">',
|
||||
'<h3 id="transcript-label-' + this.state.id + '" class="transcript-title sr"></h3>',
|
||||
'<ol id="transcript-captions" class="subtitles-menu" lang="' + this.state.lang + '"></ol>',
|
||||
'</div>'
|
||||
].join('');
|
||||
|
||||
this.loaded = false;
|
||||
this.subtitlesEl = $(HtmlUtils.ensureHtml(subtitlesHtml).toString());
|
||||
this.subtitlesEl = $(template);
|
||||
this.subtitlesMenuEl = this.subtitlesEl.find('.subtitles-menu');
|
||||
this.container = $(HtmlUtils.ensureHtml(langHtml).toString());
|
||||
this.container = $(langTemplate);
|
||||
this.captionControlEl = this.container.find('.toggle-captions');
|
||||
this.captionDisplayEl = this.state.el.find('.closed-captions');
|
||||
this.transcriptControlEl = this.container.find('.toggle-transcript');
|
||||
@@ -549,26 +542,15 @@
|
||||
}
|
||||
} else {
|
||||
if (state.isTouch) {
|
||||
HtmlUtils.setHtml(
|
||||
self.subtitlesEl.find('.subtitles-menu'),
|
||||
HtmlUtils.joinHtml(
|
||||
HtmlUtils.HTML('<li>'),
|
||||
gettext('Transcript will be displayed when you start playing the video.'),
|
||||
HtmlUtils.HTML('</li>')
|
||||
)
|
||||
);
|
||||
self.subtitlesEl.find('.subtitles-menu')
|
||||
.text(gettext('Transcript will be displayed when you start playing the video.')) // jshint ignore: line
|
||||
.wrapInner('<li></li>');
|
||||
} else {
|
||||
self.renderCaption(start, captions);
|
||||
}
|
||||
self.hideCaptions(state.hide_captions, false);
|
||||
HtmlUtils.append(
|
||||
self.state.el.find('.video-wrapper').parent(),
|
||||
HtmlUtils.HTML(self.subtitlesEl)
|
||||
);
|
||||
HtmlUtils.append(
|
||||
self.state.el.find('.secondary-controls'),
|
||||
HtmlUtils.HTML(self.container)
|
||||
);
|
||||
self.state.el.find('.video-wrapper').after(self.subtitlesEl);
|
||||
self.state.el.find('.secondary-controls').append(self.container);
|
||||
self.bindHandlers();
|
||||
}
|
||||
|
||||
@@ -648,11 +630,9 @@
|
||||
onResize: function () {
|
||||
this.subtitlesEl
|
||||
.find('.spacing').first()
|
||||
.height(this.topSpacingHeight());
|
||||
|
||||
this.subtitlesEl
|
||||
.height(this.topSpacingHeight()).end()
|
||||
.find('.spacing').last()
|
||||
.height(this.bottomSpacingHeight());
|
||||
.height(this.bottomSpacingHeight());
|
||||
|
||||
this.scrollCaption();
|
||||
this.setSubtitlesHeight();
|
||||
@@ -669,9 +649,8 @@
|
||||
renderLanguageMenu: function (languages) {
|
||||
var self = this,
|
||||
state = this.state,
|
||||
$menu = $('<ol class="langs-list menu">'),
|
||||
currentLang = state.getCurrentLanguage(),
|
||||
$li, $link, linkHtml;
|
||||
menu = $('<ol class="langs-list menu">'),
|
||||
currentLang = state.getCurrentLanguage();
|
||||
|
||||
if (_.keys(languages).length < 2) {
|
||||
// Remove the menu toggle button
|
||||
@@ -682,29 +661,20 @@
|
||||
this.showLanguageMenu = true;
|
||||
|
||||
$.each(languages, function(code, label) {
|
||||
$li = $('<li />', { 'data-lang-code': code });
|
||||
linkHtml = HtmlUtils.joinHtml(
|
||||
HtmlUtils.HTML('<button class="control control-lang">'),
|
||||
label,
|
||||
HtmlUtils.HTML('</button>')
|
||||
);
|
||||
$link = $(linkHtml.toString());
|
||||
var li = $('<li data-lang-code="' + code + '" />'),
|
||||
link = $('<button class="control control-lang">' + label + '</button>');
|
||||
|
||||
if (currentLang === code) {
|
||||
$li.addClass('is-active');
|
||||
$link.attr('aria-pressed', 'true');
|
||||
li.addClass('is-active');
|
||||
}
|
||||
|
||||
$li.append($link);
|
||||
$menu.append($li);
|
||||
li.append(link);
|
||||
menu.append(li);
|
||||
});
|
||||
|
||||
HtmlUtils.append(
|
||||
this.languageChooserEl,
|
||||
HtmlUtils.HTML($menu)
|
||||
);
|
||||
|
||||
$menu.on('click', '.control-lang', function (e) {
|
||||
this.languageChooserEl.append(menu);
|
||||
|
||||
menu.on('click', '.control-lang', function (e) {
|
||||
var el = $(e.currentTarget).parent(),
|
||||
state = self.state,
|
||||
langCode = el.data('lang-code');
|
||||
@@ -713,11 +683,7 @@
|
||||
state.lang = langCode;
|
||||
el .addClass('is-active')
|
||||
.siblings('li')
|
||||
.removeClass('is-active')
|
||||
.find('.control-lang')
|
||||
.attr('aria-pressed', 'false');
|
||||
|
||||
$(e.currentTarget).attr('aria-pressed', 'true');
|
||||
.removeClass('is-active');
|
||||
|
||||
state.el.trigger('language_menu:change', [langCode]);
|
||||
self.fetchCaption();
|
||||
@@ -727,7 +693,6 @@
|
||||
|
||||
// update the transcript lang attribute
|
||||
self.subtitlesMenuEl.attr('lang', langCode);
|
||||
self.closeLanguageMenu(e);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -750,18 +715,13 @@
|
||||
'data-index': index,
|
||||
'data-start': start[index],
|
||||
'tabindex': 0
|
||||
});
|
||||
|
||||
$(liEl).text(text);
|
||||
}).html(text);
|
||||
|
||||
return liEl[0];
|
||||
};
|
||||
|
||||
return AsyncProcess.array(captions, process).done(function (list) {
|
||||
HtmlUtils.append(
|
||||
container,
|
||||
HtmlUtils.HTML(list)
|
||||
);
|
||||
container.append(list);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -830,40 +790,17 @@
|
||||
* out of the tabbing order.
|
||||
*
|
||||
*/
|
||||
addPaddings: function() {
|
||||
var topSpacer = HtmlUtils.interpolateHtml(
|
||||
HtmlUtils.HTML([
|
||||
'<li class="spacing" style="height: {height}px">',
|
||||
'<a href="#transcript-end-{id}" id="transcript-start-{id}" class="transcript-start"></a>', // jshint ignore:line
|
||||
'</li>'
|
||||
].join('')),
|
||||
{
|
||||
id: this.state.id,
|
||||
height: this.topSpacingHeight()
|
||||
}
|
||||
);
|
||||
addPaddings: function () {
|
||||
|
||||
var bottomSpacer = HtmlUtils.interpolateHtml(
|
||||
HtmlUtils.HTML([
|
||||
'<li class="spacing" style="height: {height}px">',
|
||||
'<a href="#transcript-start-{id}" id="transcript-end-{id}" class="transcript-end"></a>', // jshint ignore:line
|
||||
'</li>'
|
||||
].join('')),
|
||||
{
|
||||
id: this.state.id,
|
||||
height: this.bottomSpacingHeight()
|
||||
}
|
||||
this.subtitlesMenuEl
|
||||
.prepend(
|
||||
$('<li class="spacing"><a href="#transcript-end-' + this.state.id + '" id="transcript-start-' + this.state.id + '" class="transcript-start"></a>') // jshint ignore: line
|
||||
.height(this.topSpacingHeight())
|
||||
)
|
||||
.append(
|
||||
$('<li class="spacing"><a href="#transcript-start-' + this.state.id + '" id="transcript-end-' + this.state.id + '" class="transcript-end"></a>') // jshint ignore: line
|
||||
.height(this.bottomSpacingHeight())
|
||||
);
|
||||
|
||||
HtmlUtils.prepend(
|
||||
this.subtitlesMenuEl,
|
||||
topSpacer
|
||||
);
|
||||
|
||||
HtmlUtils.append(
|
||||
this.subtitlesMenuEl,
|
||||
bottomSpacer
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,7 @@ import mock
|
||||
import ddt
|
||||
from config_models.models import cache
|
||||
from branding.models import BrandingApiConfig
|
||||
from openedx.core.djangoapps.theming.test_util import with_edx_domain_context
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_edx_domain_context
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
|
||||
@@ -389,7 +389,7 @@ def _get_source_address(course_id, course_title, truncate=True):
|
||||
course_title=course_title_no_quotes,
|
||||
course_name=course_name,
|
||||
from_email=theming_helpers.get_value(
|
||||
'bulk_email_default_from_email',
|
||||
'email_from_address',
|
||||
settings.BULK_EMAIL_DEFAULT_FROM_EMAIL
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ from django.test import TestCase
|
||||
import mock
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
from openedx.core.djangoapps.theming.test_util import with_is_edx_domain
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_is_edx_domain
|
||||
|
||||
|
||||
class UserMixin(object):
|
||||
|
||||
@@ -9,7 +9,7 @@ from wiki.models import URLPath
|
||||
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from openedx.core.djangoapps.theming.test_util import with_comprehensive_theme
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme
|
||||
|
||||
from courseware.tests.factories import InstructorFactory
|
||||
from course_wiki.views import get_or_create_root
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.test import TestCase
|
||||
from path import path # pylint: disable=no-name-in-module
|
||||
from django.contrib import staticfiles
|
||||
|
||||
from openedx.core.djangoapps.theming.test_util import with_comprehensive_theme
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme
|
||||
from openedx.core.lib.tempdir import mkdtemp_clean
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from openedx.core.djangoapps.theming.test_util import with_is_edx_domain
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_is_edx_domain
|
||||
|
||||
|
||||
@attr('shard_1')
|
||||
|
||||
@@ -33,7 +33,7 @@ from student_account.views import account_settings_context, get_user_orders
|
||||
from third_party_auth.tests.testutil import simulate_running_pipeline, ThirdPartyAuthTestMixin
|
||||
from util.testing import UrlResetMixin
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from openedx.core.djangoapps.theming.test_util import with_edx_domain_context
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_edx_domain_context
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
|
||||
@@ -39,7 +39,7 @@ from commerce.models import CommerceConfiguration
|
||||
from commerce.tests import TEST_PAYMENT_DATA, TEST_API_URL, TEST_API_SIGNING_KEY, TEST_PUBLIC_URL_ROOT
|
||||
from embargo.test_utils import restrict_course
|
||||
from openedx.core.djangoapps.user_api.accounts.api import get_account_settings
|
||||
from openedx.core.djangoapps.theming.test_util import with_is_edx_domain
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_is_edx_domain
|
||||
from shoppingcart.models import Order, CertificateItem
|
||||
from student.tests.factories import UserFactory, CourseEnrollmentFactory
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
/* jshint node: true */
|
||||
/*jshint -W079 */
|
||||
|
||||
'use strict';
|
||||
var path = require('path');
|
||||
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
|
||||
@@ -15,27 +16,23 @@ var options = {
|
||||
// Avoid adding files to this list. Use RequireJS.
|
||||
libraryFilesToInclude: [
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: true},
|
||||
{pattern: 'lms/js/spec/main_requirejs_coffee.js', included: true},
|
||||
|
||||
{pattern: 'js/RequireJS-namespace-undefine.js', included: true},
|
||||
|
||||
{pattern: 'common/js/vendor/jquery.js', included: true},
|
||||
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/jquery.event.drag-2.2.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/slick.core.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/slick.grid.js', included: true},
|
||||
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: true},
|
||||
|
||||
{pattern: 'xmodule_js/common_static/coffee/src/ajax_prefix.js', included: true},
|
||||
{pattern: 'common/js/vendor/jquery.js', included: true},
|
||||
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
|
||||
{pattern: 'common/js/vendor/underscore.js', included: true},
|
||||
{pattern: 'edx-ui-toolkit/js/utils/global-loader.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/src/logger.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/test/i18n.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js', included: true},
|
||||
{pattern: 'common/js/vendor/jquery.js', included: true},
|
||||
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/jquery.cookie.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/flot/jquery.flot.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/moment.min.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/moment-with-locales.min.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/URI.min.js', included: true},
|
||||
|
||||
{pattern: 'xmodule_js/common_static/js/xblock/*.js', included: true},
|
||||
@@ -45,9 +42,7 @@ var options = {
|
||||
{pattern: 'xmodule_js/src/xmodule.js', included: true},
|
||||
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/jasmine-imagediff.js', included: true},
|
||||
{pattern: 'common/js/spec_helpers/jasmine-extensions.js', included: true},
|
||||
|
||||
{pattern: 'lms/js/spec/main_requirejs_coffee.js', included: true}
|
||||
{pattern: 'common/js/spec_helpers/jasmine-extensions.js', included: true}
|
||||
],
|
||||
|
||||
libraryFiles: [
|
||||
|
||||
@@ -1,36 +1,5 @@
|
||||
(function(requirejs, define) {
|
||||
(function(requirejs) {
|
||||
'use strict';
|
||||
// We do not wish to bundle common libraries (that may also be used by non-RequireJS code on the page
|
||||
// into the optimized files. Therefore load these libraries through script tags and explicitly define them.
|
||||
// Note that when the optimizer executes this code, window will not be defined.
|
||||
if (window) {
|
||||
var defineDependency = function (globalName, name, noShim) {
|
||||
var getGlobalValue = function(name) {
|
||||
var globalNamePath = name.split('.'),
|
||||
result = window,
|
||||
i;
|
||||
for (i = 0; i < globalNamePath.length; i++) {
|
||||
result = result[globalNamePath[i]];
|
||||
}
|
||||
return result;
|
||||
},
|
||||
globalValue = getGlobalValue(globalName);
|
||||
if (globalValue) {
|
||||
if (noShim) {
|
||||
define(name, {});
|
||||
}
|
||||
else {
|
||||
define(name, [], function() { return globalValue; });
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error("Expected library to be included on page, but not found on window object: " + name);
|
||||
}
|
||||
};
|
||||
defineDependency("jQuery", "jquery");
|
||||
defineDependency("jQuery", "jquery-migrate");
|
||||
defineDependency("_", "underscore");
|
||||
}
|
||||
requirejs.config({
|
||||
baseUrl: '/base/',
|
||||
paths: {
|
||||
@@ -38,8 +7,7 @@
|
||||
"modernizr": "edx-pattern-library/js/modernizr-custom",
|
||||
"afontgarde": "edx-pattern-library/js/afontgarde",
|
||||
"edxicons": "edx-pattern-library/js/edx-icons",
|
||||
"draggabilly": "xmodule_js/common_static/js/vendor/draggabilly",
|
||||
'edx-ui-toolkit': 'edx-ui-toolkit'
|
||||
"draggabilly": "xmodule_js/common_static/js/vendor/draggabilly"
|
||||
},
|
||||
"moment": {
|
||||
exports: "moment"
|
||||
@@ -52,4 +20,4 @@
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this, RequireJS.requirejs, RequireJS.define);
|
||||
}).call(this, requirejs, define); // jshint ignore:line
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
${_("Thank you for signing up for {platform_name}.").format(platform_name=settings.PLATFORM_NAME)}
|
||||
<%! from openedx.core.djangoapps.theming.helpers import get_value as get_themed_value %>
|
||||
${_("Thank you for signing up for {platform_name}.").format(
|
||||
platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME)
|
||||
)}
|
||||
|
||||
${_("Change your life and start learning today by activating your "
|
||||
"{platform_name} account. Click on the link below or copy and "
|
||||
"paste it into your browser's address bar.").format(
|
||||
platform_name=settings.PLATFORM_NAME
|
||||
platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME)
|
||||
)}
|
||||
|
||||
% if is_secure:
|
||||
@@ -15,4 +18,4 @@ ${_("Change your life and start learning today by activating your "
|
||||
${_("If you didn't request this, you don't need to do anything; you won't "
|
||||
"receive any more email from us. Please do not reply to this e-mail; "
|
||||
"if you require assistance, check the help section of the "
|
||||
"{platform_name} website.").format(platform_name=settings.PLATFORM_NAME)}
|
||||
"{platform_name} website.").format(platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME))}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%! from openedx.core.djangoapps.theming.helpers import get_value as get_themed_value %>
|
||||
|
||||
${_("Activate Your {platform_name} Account").format(platform_name=settings.PLATFORM_NAME)}
|
||||
${_("Activate Your {platform_name} Account").format(
|
||||
platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME
|
||||
))}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%! from openedx.core.djangoapps.theming.helpers import get_value as get_themed_value %>
|
||||
${_("This is to confirm that you changed the e-mail associated with "
|
||||
"{platform_name} from {old_email} to {new_email}. If you "
|
||||
"did not make this request, please contact us immediately. Contact "
|
||||
"information is listed at:").format(platform_name=settings.PLATFORM_NAME, old_email=old_email, new_email=new_email)}
|
||||
"information is listed at:").format(
|
||||
platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME),
|
||||
old_email=old_email,
|
||||
new_email=new_email
|
||||
)
|
||||
}
|
||||
|
||||
% if is_secure:
|
||||
https://${ site }${reverse('contact')}
|
||||
@@ -11,5 +17,4 @@ ${_("This is to confirm that you changed the e-mail associated with "
|
||||
http://${ site }${reverse('contact')}
|
||||
% endif
|
||||
|
||||
${_("We keep a log of old e-mails, so if this request was unintentional, we "
|
||||
"can investigate.")}
|
||||
${_("We keep a log of old e-mails, so if this request was unintentional, we can investigate.")}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%! from openedx.core.djangoapps.theming.helpers import get_value as get_themed_value %>
|
||||
${_("We received a request to change the e-mail associated with your "
|
||||
"{platform_name} account from {old_email} to {new_email}. "
|
||||
"If this is correct, please confirm your new e-mail address by "
|
||||
"visiting:").format(platform_name=settings.PLATFORM_NAME, old_email=old_email, new_email=new_email)}
|
||||
"visiting:").format(
|
||||
platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME),
|
||||
old_email=old_email,
|
||||
new_email=new_email
|
||||
)
|
||||
}
|
||||
|
||||
% if is_secure:
|
||||
https://${ site }/email_confirm/${ key }
|
||||
@@ -13,4 +19,4 @@ ${_("We received a request to change the e-mail associated with your "
|
||||
${_("If you didn't request this, you don't need to do anything; you won't "
|
||||
"receive any more email from us. Please do not reply to this e-mail; "
|
||||
"if you require assistance, check the help section of the "
|
||||
"{platform_name} web site.").format(platform_name=settings.PLATFORM_NAME)}
|
||||
"{platform_name} web site.").format(platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME))}
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
${_("Request to change {platform_name} account e-mail").format(platform_name=settings.PLATFORM_NAME)}
|
||||
<%! from openedx.core.djangoapps.theming.helpers import get_value as get_themed_value %>
|
||||
${_("Request to change {platform_name} account e-mail").format(
|
||||
platform_name=get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME)
|
||||
)}
|
||||
|
||||
@@ -125,7 +125,7 @@ def send_credit_notifications(username, course_key):
|
||||
notification_msg.attach(logo_image)
|
||||
|
||||
# add email addresses of sender and receiver
|
||||
from_address = theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL)
|
||||
from_address = theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)
|
||||
to_address = user.email
|
||||
|
||||
# send the root email message
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"""
|
||||
Helpers for accessing comprehensive theming related variables.
|
||||
Helpers for accessing comprehensive theming related variables.
|
||||
"""
|
||||
from microsite_configuration import microsite
|
||||
from microsite_configuration import page_title_breadcrumbs
|
||||
from django.conf import settings
|
||||
|
||||
from microsite_configuration import microsite, page_title_breadcrumbs
|
||||
|
||||
|
||||
def get_page_title_breadcrumbs(*args):
|
||||
"""
|
||||
@@ -17,7 +17,25 @@ def get_value(val_name, default=None, **kwargs):
|
||||
"""
|
||||
This is a proxy function to hide microsite_configuration behind comprehensive theming.
|
||||
"""
|
||||
return microsite.get_value(val_name, default=default, **kwargs)
|
||||
|
||||
# Retrieve the requested field/value from the microsite configuration
|
||||
microsite_value = microsite.get_value(val_name, default=default, **kwargs)
|
||||
|
||||
# Attempt to perform a dictionary update using the provided default
|
||||
# This will fail if either the default or the microsite value is not a dictionary
|
||||
try:
|
||||
value = dict(default)
|
||||
value.update(microsite_value)
|
||||
|
||||
# If the dictionary update fails, just use the microsite value
|
||||
# TypeError: default is not iterable (simple value or None)
|
||||
# ValueError: default is iterable but not a dict (list, not dict)
|
||||
# AttributeError: default does not have an 'update' method
|
||||
except (TypeError, ValueError, AttributeError):
|
||||
value = microsite_value
|
||||
|
||||
# Return the end result to the caller
|
||||
return value
|
||||
|
||||
|
||||
def get_template_path(relative_path, **kwargs):
|
||||
|
||||
0
openedx/core/djangoapps/theming/tests/__init__.py
Normal file
0
openedx/core/djangoapps/theming/tests/__init__.py
Normal file
25
openedx/core/djangoapps/theming/tests/test_helpers.py
Normal file
25
openedx/core/djangoapps/theming/tests/test_helpers.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""
|
||||
Test helpers for Comprehensive Theming.
|
||||
"""
|
||||
from django.test import TestCase
|
||||
from mock import patch
|
||||
|
||||
from openedx.core.djangoapps.theming import helpers
|
||||
|
||||
|
||||
class ThemingHelpersTests(TestCase):
|
||||
"""
|
||||
Make sure some of the theming helper functions work
|
||||
"""
|
||||
|
||||
def test_get_value_returns_override(self):
|
||||
"""
|
||||
Tests to make sure the get_value() operation returns a combined dictionary consisting
|
||||
of the base container with overridden keys from the microsite configuration
|
||||
"""
|
||||
with patch('microsite_configuration.microsite.get_value') as mock_get_value:
|
||||
override_key = 'JWT_ISSUER'
|
||||
override_value = 'testing'
|
||||
mock_get_value.return_value = {override_key: override_value}
|
||||
jwt_auth = helpers.get_value('JWT_AUTH')
|
||||
self.assertEqual(jwt_auth[override_key], override_value)
|
||||
@@ -15,7 +15,7 @@ from django.test.utils import override_settings
|
||||
|
||||
import edxmako
|
||||
|
||||
from .core import comprehensive_theme_changes
|
||||
from openedx.core.djangoapps.theming.core import comprehensive_theme_changes
|
||||
|
||||
EDX_THEME_DIR = settings.REPO_ROOT / "themes" / "edx.org"
|
||||
|
||||
@@ -398,7 +398,7 @@ def request_password_change(email, orig_host, is_secure):
|
||||
# Generate a single-use link for performing a password reset
|
||||
# and email it to the user.
|
||||
form.save(
|
||||
from_email=theming_helpers.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL),
|
||||
from_email=theming_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL),
|
||||
domain_override=orig_host,
|
||||
use_https=is_secure
|
||||
)
|
||||
|
||||
@@ -43,7 +43,7 @@ edx-drf-extensions==0.5.1
|
||||
edx-lint==0.4.3
|
||||
edx-django-oauth2-provider==1.1.1
|
||||
edx-django-sites-extensions==2.0.1
|
||||
edx-oauth2-provider==1.1.1
|
||||
edx-oauth2-provider==1.1.2
|
||||
edx-opaque-keys==0.2.1
|
||||
edx-organizations==0.4.1
|
||||
edx-rest-api-client==1.2.1
|
||||
|
||||
@@ -90,7 +90,7 @@ git+https://github.com/edx/xblock-utils.git@v1.0.2#egg=xblock-utils==1.0.2
|
||||
-e git+https://github.com/edx/edx-reverification-block.git@0.0.5#egg=edx-reverification-block==0.0.5
|
||||
git+https://github.com/edx/edx-user-state-client.git@1.0.1#egg=edx-user-state-client==1.0.1
|
||||
git+https://github.com/edx/xblock-lti-consumer.git@v1.0.9#egg=xblock-lti-consumer==1.0.9
|
||||
git+https://github.com/edx/edx-proctoring.git@0.12.19#egg=edx-proctoring==0.12.19
|
||||
git+https://github.com/edx/edx-proctoring.git@0.12.21#egg=edx-proctoring==0.12.21
|
||||
|
||||
# Third Party XBlocks
|
||||
-e git+https://github.com/mitodl/edx-sga@172a90fd2738f8142c10478356b2d9ed3e55334a#egg=edx-sga
|
||||
|
||||
Reference in New Issue
Block a user