Adds plugin functions to register javascript and CSS in the admin panel. Move global plugin script/stylesheet lists into application factory specific lists. Closes #804 (#805)

* Adds plugin functions to register javascript and CSS in the admin panel
* Move global plugin script/stylesheet lists into application factory specific lists
* Closes #804
This commit is contained in:
Kevin Chung
2018-12-15 13:48:21 -05:00
committed by GitHub
parent 367110969e
commit f4f4bd5333
5 changed files with 114 additions and 18 deletions

View File

@@ -3,20 +3,19 @@ import importlib
import os
from collections import namedtuple
from flask.helpers import safe_join
from flask import current_app as app, send_file, send_from_directory, abort
from CTFd.utils.decorators import admins_only as admins_only_wrapper
from CTFd.utils.plugins import (
override_template as utils_override_template,
register_script as utils_register_plugin_script,
register_stylesheet as utils_register_plugin_stylesheet,
register_admin_script as utils_register_admin_plugin_script,
register_admin_stylesheet as utils_register_admin_plugin_stylesheet
)
from CTFd.utils.config.pages import get_pages
Menu = namedtuple('Menu', ['title', 'route'])
ADMIN_PLUGIN_MENU_BAR = []
USER_PAGE_MENU_BAR = []
def register_plugin_assets_directory(app, base_path, admins_only=False):
@@ -83,6 +82,26 @@ def register_plugin_stylesheet(*args, **kwargs):
utils_register_plugin_stylesheet(*args, **kwargs)
def register_admin_plugin_script(*args, **kwargs):
"""
Adds a given script to the base.html of the admin theme which all admin pages inherit from
:param args:
:param kwargs:
:return:
"""
utils_register_admin_plugin_script(*args, **kwargs)
def register_admin_plugin_stylesheet(*args, **kwargs):
"""
Adds a given stylesheet to the base.html of the admin theme which all admin pages inherit from
:param args:
:param kwargs:
:return:
"""
utils_register_admin_plugin_stylesheet(*args, **kwargs)
def register_admin_plugin_menu_bar(title, route):
"""
Registers links on the Admin Panel menubar/navbar
@@ -92,7 +111,7 @@ def register_admin_plugin_menu_bar(title, route):
:return:
"""
am = Menu(title=title, route=route)
ADMIN_PLUGIN_MENU_BAR.append(am)
app.admin_plugin_menu_bar.append(am)
def get_admin_plugin_menu_bar():
@@ -101,7 +120,7 @@ def get_admin_plugin_menu_bar():
:return: Returns a list of Menu namedtuples. They have name, and route attributes.
"""
return ADMIN_PLUGIN_MENU_BAR
return app.admin_plugin_menu_bar
def register_user_page_menu_bar(title, route):
@@ -113,7 +132,7 @@ def register_user_page_menu_bar(title, route):
:return:
"""
p = Menu(title=title, route=route)
USER_PAGE_MENU_BAR.append(p)
app.plugin_menu_bar.append(p)
def get_user_page_menu_bar():
@@ -122,7 +141,7 @@ def get_user_page_menu_bar():
:return: Returns a list of Menu namedtuples. They have name, and route attributes.
"""
return get_pages() + USER_PAGE_MENU_BAR
return get_pages() + app.plugin_menu_bar
def bypass_csrf_protection(f):
@@ -146,6 +165,14 @@ def init_plugins(app):
:param app: A CTFd application
:return:
"""
app.admin_plugin_scripts = []
app.admin_plugin_stylesheets = []
app.plugin_scripts = []
app.plugin_stylesheets = []
app.admin_plugin_menu_bar = []
app.plugin_menu_bar = []
if app.config.get('SAFE_MODE', False) is False:
modules = sorted(glob.glob(os.path.dirname(__file__) + "/*"))
blacklist = {'__pycache__'}

View File

@@ -25,6 +25,15 @@
var user_mode = "{{ get_config('user_mode') }}";
</script>
{% block stylesheets %} {% endblock %}
{% for stylesheet in get_registered_admin_stylesheets() %}
{% if stylesheet.startswith('http') %}
<link rel="stylesheet" type="text/css" href="{{ stylesheet }}">
{% elif request.script_root %}
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/{{ stylesheet }}">
{% else %}
<link rel="stylesheet" type="text/css" href="{{ stylesheet }}">
{% endif %}
{% endfor %}
</head>
<body>
@@ -135,6 +144,16 @@
<script src="{{ url_for('views.themes', theme='admin', path='js/ezq.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/style.js') }}"></script>
{% block scripts %} {% endblock %}
{% for script in get_registered_admin_scripts() %}
{% if script.startswith('http') %}
<script src="{{ script }}"></script>
{% elif request.script_root %}
<script src="{{ request.script_root }}/{{ script }}"></script>
{% else %}
<script src="{{ script }}"></script>
{% endif %}
{% endfor %}
</body>
</html>

View File

@@ -8,7 +8,13 @@ from CTFd.utils import config
from CTFd.utils.config import can_send_mail, ctf_logo, ctf_name, ctf_theme
from CTFd.utils.config.pages import get_pages
from CTFd.utils.plugins import get_registered_stylesheets, get_registered_scripts, get_configurable_plugins
from CTFd.utils.plugins import (
get_registered_stylesheets,
get_registered_scripts,
get_configurable_plugins,
get_registered_admin_scripts,
get_registered_admin_stylesheets
)
from CTFd.utils.countries import get_countries, lookup_country_code
from CTFd.utils.user import authed, get_ip, get_current_user, get_current_team
@@ -45,6 +51,8 @@ def init_template_globals(app):
app.jinja_env.globals.update(get_configurable_plugins=get_configurable_plugins)
app.jinja_env.globals.update(get_registered_scripts=get_registered_scripts)
app.jinja_env.globals.update(get_registered_stylesheets=get_registered_stylesheets)
app.jinja_env.globals.update(get_registered_admin_scripts=get_registered_admin_scripts)
app.jinja_env.globals.update(get_registered_admin_stylesheets=get_registered_admin_stylesheets)
app.jinja_env.globals.update(get_config=get_config)
app.jinja_env.globals.update(generate_account_url=generate_account_url)
app.jinja_env.globals.update(get_countries=get_countries)

View File

@@ -4,24 +4,36 @@ import os
import json
SCRIPTS = []
STYLESHEETS = []
def register_script(url):
SCRIPTS.append(url)
app.plugin_scripts.append(url)
def register_stylesheet(url):
STYLESHEETS.append(url)
app.plugin_stylesheets.append(url)
def register_admin_script(url):
app.admin_plugin_scripts.append(url)
def register_admin_stylesheet(url):
app.admin_plugin_stylesheets.append(url)
def get_registered_scripts():
return SCRIPTS
return app.plugin_scripts
def get_registered_stylesheets():
return STYLESHEETS
return app.plugin_stylesheets
def get_registered_admin_scripts():
return app.admin_plugin_scripts
def get_registered_admin_stylesheets():
return app.admin_plugin_stylesheets
def override_template(template, html):

View File

@@ -7,6 +7,8 @@ from CTFd.plugins import (
register_plugin_asset,
register_plugin_script,
register_plugin_stylesheet,
register_admin_plugin_script,
register_admin_plugin_stylesheet,
override_template,
register_admin_plugin_menu_bar,
get_admin_plugin_menu_bar,
@@ -77,7 +79,7 @@ def test_admin_override_template():
def test_register_plugin_script():
'''Test that register_plugin_script adds script paths to the core theme when used from a plugin'''
"""Test that register_plugin_script adds script paths to the core theme when used from a plugin"""
app = create_ctfd()
with app.app_context():
register_plugin_script('/fake/script/path.js')
@@ -91,7 +93,7 @@ def test_register_plugin_script():
def test_register_plugin_stylesheet():
'''Test that register_plugin_stylesheet adds stylesheet paths to the core theme when used from a plugin'''
"""Test that register_plugin_stylesheet adds stylesheet paths to the core theme when used from a plugin"""
app = create_ctfd()
with app.app_context():
register_plugin_script('/fake/stylesheet/path.css')
@@ -104,6 +106,34 @@ def test_register_plugin_stylesheet():
destroy_ctfd(app)
def test_register_admin_plugin_script():
"""Test that register_admin_plugin_script adds script paths to the admin theme when used from a plugin"""
app = create_ctfd()
with app.app_context():
register_admin_plugin_script('/fake/script/path.js')
register_admin_plugin_script('http://ctfd.io/fake/script/path.js')
with login_as_user(app, name="admin") as client:
r = client.get('/admin/statistics')
output = r.get_data(as_text=True)
assert '/fake/script/path.js' in output
assert 'http://ctfd.io/fake/script/path.js' in output
destroy_ctfd(app)
def test_register_admin_plugin_stylesheet():
"""Test that register_admin_plugin_stylesheet adds stylesheet paths to the admin theme when used from a plugin"""
app = create_ctfd()
with app.app_context():
register_admin_plugin_stylesheet('/fake/stylesheet/path.css')
register_admin_plugin_stylesheet('http://ctfd.io/fake/stylesheet/path.css')
with login_as_user(app, name="admin") as client:
r = client.get('/admin/statistics')
output = r.get_data(as_text=True)
assert '/fake/stylesheet/path.css' in output
assert 'http://ctfd.io/fake/stylesheet/path.css' in output
destroy_ctfd(app)
def test_register_admin_plugin_menu_bar():
"""
Test that register_admin_plugin_menu_bar() properly inserts into HTML and get_admin_plugin_menu_bar()