From bacd4334ed4121e4b5071b8a4d9abe2e56b75f71 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 21 Dec 2017 15:29:53 -0500 Subject: [PATCH 1/5] Add a form of static:require_module that assumes that the factory is self-initializing --- cms/envs/common.py | 3 ++ cms/templates/base.html | 1 + .../templates/static_content.html | 34 +++++++++++++++++-- common/static/common/js/utils/page_factory.js | 27 +++++++++++++++ conftest.py | 2 +- 5 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 common/static/common/js/utils/page_factory.js diff --git a/cms/envs/common.py b/cms/envs/common.py index efe84ee5e4..75a1da4d55 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -1126,6 +1126,9 @@ INSTALLED_APPS = [ # Entitlements, used in openedx tests 'entitlements', + + # Asset management for mako templates + 'pipeline_mako', ] diff --git a/cms/templates/base.html b/cms/templates/base.html index 64a2a03668..1736677f2a 100644 --- a/cms/templates/base.html +++ b/cms/templates/base.html @@ -143,6 +143,7 @@ from openedx.core.djangolib.markup import HTML }); }); + <%block name='requirejs_page'> <%include file="widgets/segment-io-footer.html" /> diff --git a/common/djangoapps/pipeline_mako/templates/static_content.html b/common/djangoapps/pipeline_mako/templates/static_content.html index 514cdf6cd5..83f85fd9ad 100644 --- a/common/djangoapps/pipeline_mako/templates/static_content.html +++ b/common/djangoapps/pipeline_mako/templates/static_content.html @@ -111,7 +111,7 @@ source, template_path = Loader(engine).load_template_source(path) ${HTML(render_bundle(page))} -<%def name="webpack(entry)"> +<%def name="webpack(entry, extension=None, config='DEFAULT', attrs='')"> <%doc> Loads Javascript onto your page from a Webpack-generated bundle. Uses the Django template engine because our webpack loader only provides template tags for Jinja and Django. @@ -119,7 +119,7 @@ source, template_path = Loader(engine).load_template_source(path) <% body = capture(caller.body) %> - ${HTML(render_bundle(entry))} + ${HTML(render_bundle(entry, extension=None, config='DEFAULT', attrs=attrs))} % if body: +<%def name="require_page(page_name, class_name)"> + <%doc> + Loads Javascript onto your page synchronously. + Uses RequireJS in development and a plain script tag in production. + The body of the tag should be a comma-separated list of arguments + to be passed to the page factory specified by the class_name argument. + + <% + body = capture(caller.body) + %> + + % if not settings.REQUIRE_DEBUG: + + % endif + + + <%def name="require_module(module_name, class_name)"> <%doc> Loads Javascript onto your page synchronously. diff --git a/common/static/common/js/utils/page_factory.js b/common/static/common/js/utils/page_factory.js new file mode 100644 index 0000000000..8b3e72c827 --- /dev/null +++ b/common/static/common/js/utils/page_factory.js @@ -0,0 +1,27 @@ +define([], function() { + 'use strict'; + + return function invokePageFactory(name, factory) { + var args; + + if (typeof window.pageFactoryArguments === 'undefined') { + throw Error( + 'window.pageFactoryArguments must be initialized before calling invokePageFactory(' + + name + + '). Use the <%static:require_page> template tag.' + ); + } + args = window.pageFactoryArguments[name]; + + if (typeof args === 'undefined') { + throw Error( + 'window.pageFactoryArguments["' + + name + + '"] must be initialized before calling invokePageFactory(' + + name + + '). Use the <%static:require_page> template tag.' + ); + } + factory.apply(null, window.pageFactoryArguments[name]); + }; +}); diff --git a/conftest.py b/conftest.py index 1f32a76982..513e5f762d 100644 --- a/conftest.py +++ b/conftest.py @@ -14,5 +14,5 @@ from cms.conftest import _django_clear_site_cache, pytest_configure # pylint: d def no_webpack_loader(monkeypatch): monkeypatch.setattr( "webpack_loader.templatetags.webpack_loader.render_bundle", - lambda x: '' + lambda entry, extension=None, config='DEFAULT', attrs='': '' ) From 58bb7167c107c4e203d14365280869d4fc053ec8 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 21 Dec 2017 15:36:40 -0500 Subject: [PATCH 2/5] Convert cms login.html to the require_page pattern in preparation for webpack --- cms/static/cms/js/build.js | 2 +- cms/static/js/factories/login.js | 2 +- cms/static/js/pages/login.js | 11 +++++++++++ cms/templates/login.html | 9 +++++---- common/test/test-theme/cms/templates/login.html | 10 ++++++---- themes/red-theme/cms/templates/login.html | 10 ++++++---- 6 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 cms/static/js/pages/login.js diff --git a/cms/static/cms/js/build.js b/cms/static/cms/js/build.js index a88009f2b3..d0221be3a9 100644 --- a/cms/static/cms/js/build.js +++ b/cms/static/cms/js/build.js @@ -28,7 +28,7 @@ 'js/certificates/factories/certificates_page_factory', 'js/factories/index', 'js/factories/library', - 'js/factories/login', + 'js/pages/login', 'js/factories/manage_users', 'js/factories/outline', 'js/factories/register', diff --git a/cms/static/js/factories/login.js b/cms/static/js/factories/login.js index 7d080cdb2b..fdbcef31e8 100644 --- a/cms/static/js/factories/login.js +++ b/cms/static/js/factories/login.js @@ -1,6 +1,6 @@ define(['jquery.cookie', 'utility', 'common/js/components/utils/view_utils'], function(cookie, utility, ViewUtils) { 'use strict'; - return function(homepageURL) { + return function LoginFactory(homepageURL) { function postJSON(url, data, callback) { $.ajax({ type: 'POST', diff --git a/cms/static/js/pages/login.js b/cms/static/js/pages/login.js new file mode 100644 index 0000000000..8c53644675 --- /dev/null +++ b/cms/static/js/pages/login.js @@ -0,0 +1,11 @@ +(function(define) { + 'use strict'; + + define( + ['js/factories/login', 'common/js/utils/page_factory'], + function(LoginFactory, invokePageFactory) { + invokePageFactory('LoginFactory', LoginFactory); + } + ); +}).call(this, define || RequireJS.define); + diff --git a/cms/templates/login.html b/cms/templates/login.html index 205e64f3cd..91b54b5c74 100644 --- a/cms/templates/login.html +++ b/cms/templates/login.html @@ -54,8 +54,9 @@ from openedx.core.djangolib.js_utils import js_escaped_string -<%block name="requirejs"> - require(["js/factories/login"], function(LoginFactory) { - LoginFactory("${reverse('homepage') | n, js_escaped_string}"); - }); +<%block name="requirejs_page"> + <%static:require_page page_name="js/pages/login" class_name="LoginFactory"> + ## xss-lint: disable=mako-invalid-js-filter, mako-invalid-html-filter + "${reverse('homepage') | n, js_escaped_string}" + diff --git a/common/test/test-theme/cms/templates/login.html b/common/test/test-theme/cms/templates/login.html index a5faf86f1c..95ba9e9795 100644 --- a/common/test/test-theme/cms/templates/login.html +++ b/common/test/test-theme/cms/templates/login.html @@ -1,3 +1,4 @@ +<%namespace name='static' file='/static_content.html'/> <%page expression_filter="h"/> <%inherit file="base.html" /> @@ -51,8 +52,9 @@ from openedx.core.djangolib.js_utils import js_escaped_string -<%block name="requirejs"> - require(["js/factories/login"], function(LoginFactory) { - LoginFactory("${reverse('homepage') | n, js_escaped_string }"); - }); +<%block name="requirejs_page"> + <%static:require_page page_name="js/pages/login" class_name="LoginFactory"> + ## xss-lint: disable=mako-invalid-js-filter, mako-invalid-html-filter + "${reverse('homepage') | n, js_escaped_string}" + diff --git a/themes/red-theme/cms/templates/login.html b/themes/red-theme/cms/templates/login.html index 8f9274f7a4..ae55043263 100644 --- a/themes/red-theme/cms/templates/login.html +++ b/themes/red-theme/cms/templates/login.html @@ -1,3 +1,4 @@ +<%namespace name='static' file='/static_content.html'/> <%page expression_filter="h"/> <%inherit file="base.html" /> @@ -50,8 +51,9 @@ from django.utils.translation import ugettext as _ -<%block name="requirejs"> - require(["js/factories/login"], function(LoginFactory) { - LoginFactory("${reverse('homepage')}"); - }); +<%block name="requirejs_page"> + <%static:require_page page_name="js/pages/login" class_name="LoginFactory"> + ## xss-lint: disable=mako-invalid-js-filter, mako-invalid-html-filter + "${reverse('homepage') | n, js_escaped_string}" + From 2d89f1b2ab1fedfe0645fd1ee842938f3f7eded7 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Wed, 17 Jan 2018 15:10:38 -0500 Subject: [PATCH 3/5] Put Require.js in debug mode in acceptance tests, because they don't run with optimized assets --- cms/envs/acceptance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cms/envs/acceptance.py b/cms/envs/acceptance.py index 7846766a7c..4cabd08403 100644 --- a/cms/envs/acceptance.py +++ b/cms/envs/acceptance.py @@ -148,3 +148,4 @@ SECRET_KEY = uuid.uuid4().hex ############################### PIPELINE ####################################### PIPELINE_ENABLED = False +REQUIRE_DEBUG = True From 158ba153f58bf11f3322b03daa6c0eafefed19aa Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 18 Jan 2018 15:12:18 -0500 Subject: [PATCH 4/5] Allow space-separate xsslint pragrma disabling --- scripts/xss_linter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/xss_linter.py b/scripts/xss_linter.py index aa89801332..ceb697a14a 100755 --- a/scripts/xss_linter.py +++ b/scripts/xss_linter.py @@ -314,7 +314,7 @@ class RuleViolation(object): found. """ - pragma_match = re.search(r'xss-lint:\s*disable=([a-zA-Z,-]+)', string) + pragma_match = re.search(r'xss-lint:\s*disable=([a-zA-Z,\- ]+)', string) if pragma_match is None: return if scope_start_string: @@ -324,7 +324,7 @@ class RuleViolation(object): return for disabled_rule in pragma_match.group(1).split(','): - if disabled_rule == self.rule.rule_id: + if disabled_rule.strip() == self.rule.rule_id: self.is_disabled = True return From 974f099835fe62491a7d3fced0ef43fd7e3308ad Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Tue, 23 Jan 2018 15:58:12 -0500 Subject: [PATCH 5/5] Teach the xss_linter about the require_page tag --- cms/templates/login.html | 1 - common/test/test-theme/cms/templates/login.html | 1 - scripts/xss_linter.py | 2 ++ themes/red-theme/cms/templates/login.html | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cms/templates/login.html b/cms/templates/login.html index 91b54b5c74..7981ae6dc4 100644 --- a/cms/templates/login.html +++ b/cms/templates/login.html @@ -56,7 +56,6 @@ from openedx.core.djangolib.js_utils import js_escaped_string <%block name="requirejs_page"> <%static:require_page page_name="js/pages/login" class_name="LoginFactory"> - ## xss-lint: disable=mako-invalid-js-filter, mako-invalid-html-filter "${reverse('homepage') | n, js_escaped_string}" diff --git a/common/test/test-theme/cms/templates/login.html b/common/test/test-theme/cms/templates/login.html index 95ba9e9795..8479674153 100644 --- a/common/test/test-theme/cms/templates/login.html +++ b/common/test/test-theme/cms/templates/login.html @@ -54,7 +54,6 @@ from openedx.core.djangolib.js_utils import js_escaped_string <%block name="requirejs_page"> <%static:require_page page_name="js/pages/login" class_name="LoginFactory"> - ## xss-lint: disable=mako-invalid-js-filter, mako-invalid-html-filter "${reverse('homepage') | n, js_escaped_string}" diff --git a/scripts/xss_linter.py b/scripts/xss_linter.py index ceb697a14a..2d6433d6a3 100755 --- a/scripts/xss_linter.py +++ b/scripts/xss_linter.py @@ -2380,6 +2380,8 @@ class MakoTemplateLinter(BaseLinter): | # script tag end <%static:require_module(_async)?.*?> | # require js script tag start (optionally the _async version) | # require js script tag end (optionally the _async version) + <%static:require_page.*?> | # require js script tag start + | # require js script tag end <%static:webpack.*?> | # webpack script tag start | # webpack script tag end <%static:studiofrontend.*?> | # studiofrontend script tag start diff --git a/themes/red-theme/cms/templates/login.html b/themes/red-theme/cms/templates/login.html index ae55043263..b50ed21855 100644 --- a/themes/red-theme/cms/templates/login.html +++ b/themes/red-theme/cms/templates/login.html @@ -53,7 +53,6 @@ from django.utils.translation import ugettext as _ <%block name="requirejs_page"> <%static:require_page page_name="js/pages/login" class_name="LoginFactory"> - ## xss-lint: disable=mako-invalid-js-filter, mako-invalid-html-filter "${reverse('homepage') | n, js_escaped_string}"