Skip to content

Commit

Permalink
Override templates in a custom directory
Browse files Browse the repository at this point in the history
This commit allows the override and the addition of templates using a
custom directory that will be added to the loader. See the
`TEMPLATES_CUSTOM_DIRECTORIES` configuration value in the example
configuration file.

Signed-off-by: Aurélien Bompard <aurelien@bompard.org>
  • Loading branch information
abompard committed Jul 21, 2021
1 parent 31c3b89 commit 855eee4
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 2 deletions.
1 change: 1 addition & 0 deletions news/PR701.feature
@@ -0,0 +1 @@
Allow template override with a custom directory, see the ``TEMPLATES_CUSTOM_DIRECTORIES`` configration value
15 changes: 15 additions & 0 deletions noggin.cfg.example
Expand Up @@ -87,6 +87,21 @@ MAIL_SUPPRESS_SEND = True
# will only be accessible to users that have this role.
# STAGE_USERS_ROLE = "Stage User Managers"

# Additional directories to look up folders in. The templates in these directories
# will override the app's template with the same filename. You can also create the
# following templates to insert HTML in the output:
# - `after-navbar.html`: will be inserted between the navbar and the main content
# on every page
# - `before-footer.html`: will be inserted between the main content and the footer
# on every page
# - `head.html`: will be inserted at the end of the <head> tag on every page
# TEMPLATES_CUSTOM_DIRECTORIES = []

# The following sources will be added to the Content Security Policy for images.
# This can be useful if you want to add images in custom templates.
# https://content-security-policy.com/img-src/
# ACCEPT_IMAGES_FROM = []

# Spam checking
# BASSET_URL = None
# SPAMCHECK_TOKEN_EXPIRATION = 60 # in minutes
Expand Down
18 changes: 16 additions & 2 deletions noggin/app.py
Expand Up @@ -2,6 +2,7 @@
from logging.config import dictConfig

import flask_talisman
import jinja2
from flask import Flask
from flask_healthz import healthz
from flask_mail import Mail
Expand Down Expand Up @@ -55,6 +56,15 @@ def create_app(config=None):
if app.config.get("TEMPLATES_AUTO_RELOAD"):
app.jinja_env.auto_reload = True

# Custom template folders
if app.config["TEMPLATES_CUSTOM_DIRECTORIES"]:
app.jinja_loader = jinja2.ChoiceLoader(
[
jinja2.FileSystemLoader(app.config["TEMPLATES_CUSTOM_DIRECTORIES"]),
app.jinja_loader,
]
)

# Logging
if app.config.get("LOGGING"):
dictConfig(app.config["LOGGING"])
Expand Down Expand Up @@ -83,9 +93,13 @@ def create_app(config=None):
# https://csp.withgoogle.com/docs/strict-csp.html#example
"'strict-dynamic'",
],
"img-src": ["'self'", "seccdn.libravatar.org"],
"img-src": ["'self'", "seccdn.libravatar.org"]
+ app.config["ACCEPT_IMAGES_FROM"],
# The style-src directive needs to be specified (even if it's the same as default-src)
# to add the nonce.
"style-src": "'self'",
},
content_security_policy_nonce_in=['script-src'],
content_security_policy_nonce_in=['script-src', 'style-src'],
)

# Template filters
Expand Down
3 changes: 3 additions & 0 deletions noggin/defaults.py
Expand Up @@ -36,6 +36,9 @@

STAGE_USERS_ROLE = "Stage User Managers"

TEMPLATES_CUSTOM_DIRECTORIES = []
ACCEPT_IMAGES_FROM = []

BASSET_URL = None
SPAMCHECK_TOKEN_EXPIRATION = 60 # in minutes

Expand Down
3 changes: 3 additions & 0 deletions noggin/templates/base.html
Expand Up @@ -8,10 +8,13 @@
<link href="{{ url_for('static', filename='fonts/font-awesome.css') }}" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/main.css') }}" rel="stylesheet" type="text/css">
<title>{% block title %}{% endblock %}{% if self.title() %} - {% endif %}{% block website %}noggin{% endblock %}</title>
{% include "head.html" ignore missing %}
</head>
<body>
{% block navbar %} {% endblock %}
{% include "after-navbar.html" ignore missing %}
{% block bodycontent %}{% endblock %}
{% include "before-footer.html" ignore missing %}
{% block footer %}{% endblock %}
{% block scripts %}
{% if current_user %}
Expand Down
30 changes: 30 additions & 0 deletions noggin/tests/unit/test_app.py
Expand Up @@ -36,3 +36,33 @@ def test_logging(mocker, app_config):
logging_config = mocker.patch("noggin.app.dictConfig")
create_app(config)
logging_config.assert_called_once_with("dummy-logging-config")


def test_templates_custom_directory_insertion(app_config, tmp_path):
tpl_dir = tmp_path / "templates"
os.makedirs(tpl_dir)
config = app_config.copy()
config["TEMPLATES_CUSTOM_DIRECTORIES"] = [tpl_dir]
app = create_app(config)
# Use the template placeholder
with open(tpl_dir / "after-navbar.html", "w") as tpl:
tpl.write("TESTING TEMPLATES CUSTOM DIR\n")
with app.test_client() as client:
response = client.get('/')
assert response.status_code == 200
assert "TESTING TEMPLATES CUSTOM DIR" in response.get_data(as_text=True)


def test_templates_custom_directory_override(app_config, tmp_path):
tpl_dir = tmp_path / "templates"
os.makedirs(tpl_dir)
config = app_config.copy()
config["TEMPLATES_CUSTOM_DIRECTORIES"] = [tpl_dir]
app = create_app(config)
# Override the whole page template
with open(tpl_dir / "index.html", "w") as tpl:
tpl.write("TESTING TEMPLATES CUSTOM DIR\n")
with app.test_client() as client:
response = client.get('/')
assert response.status_code == 200
assert response.get_data(as_text=True) == "TESTING TEMPLATES CUSTOM DIR"

0 comments on commit 855eee4

Please sign in to comment.