From fb24f718ae6adc4398a43805071c1aa727ac7f1f Mon Sep 17 00:00:00 2001 From: amercader Date: Thu, 18 Aug 2016 12:39:18 +0100 Subject: [PATCH] [#3196] Add DebugToolbar to the Flask stack Similarly to Django debug toolbar, it offers a lot of really useful information when debugging. https://flask-debugtoolbar.readthedocs.io It requires SECRET_KEY to be set up, which we will need for the sessions anyway. As with the repoze.who auth token, we fall back to `beaker.session.secret` if it's not present. --- ckan/config/middleware/flask_app.py | 20 ++++++++++++++++++ ckan/tests/config/test_middleware.py | 31 +++++++++++++++++++++++++++- dev-requirements.txt | 1 + 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/ckan/config/middleware/flask_app.py b/ckan/config/middleware/flask_app.py index 6a3e80b4369..52712bf5a12 100644 --- a/ckan/config/middleware/flask_app.py +++ b/ckan/config/middleware/flask_app.py @@ -3,6 +3,10 @@ from flask import Flask from werkzeug.exceptions import HTTPException +from flask_debugtoolbar import DebugToolbarExtension + +from paste.deploy.converters import asbool + from ckan.common import config @@ -14,7 +18,10 @@ def make_flask_stack(conf, **app_conf): """ This has to pass the flask app through all the same middleware that Pylons used """ + debug = asbool(app_conf.get('debug', app_conf.get('DEBUG', False))) + app = flask_app = CKANFlask(__name__) + app.debug = debug # Update Flask config with the CKAN values. We use the common config # object as values might have been modified on `load_environment` @@ -24,6 +31,19 @@ def make_flask_stack(conf, **app_conf): app.config.update(conf) app.config.update(app_conf) + # Do all the Flask-specific stuff before adding other middlewares + + # Secret key needed for flask-debug-toolbar and sessions + if not app.config.get('SECRET_KEY'): + app.config['SECRET_KEY'] = config.get('beaker.session.secret') + if not app.config.get('SECRET_KEY'): + raise RuntimeError(u'You must provide a value for the secret key' + ' with the SECRET_KEY config option') + + if debug: + app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False + DebugToolbarExtension(app) + @app.route('/hello', methods=['GET']) def hello_world(): return 'Hello World, this is served by Flask' diff --git a/ckan/tests/config/test_middleware.py b/ckan/tests/config/test_middleware.py index fad66fa4b6d..9e3e1166793 100644 --- a/ckan/tests/config/test_middleware.py +++ b/ckan/tests/config/test_middleware.py @@ -2,11 +2,12 @@ import mock import wsgiref -from nose.tools import assert_equals, assert_not_equals, eq_ +from nose.tools import assert_equals, assert_not_equals, eq_, assert_raises from routes import url_for import ckan.plugins as p import ckan.tests.helpers as helpers +from ckan.common import config from ckan.config.middleware import AskAppDispatcherMiddleware from ckan.config.middleware.flask_app import CKANFlask @@ -409,3 +410,31 @@ class MockPylonsController(p.toolkit.BaseController): def view(self): return 'Hello World, this is served from a Pylons extension' + + +class TestSecretKey(object): + + @helpers.change_config('SECRET_KEY', 'super_secret_stuff') + def test_secret_key_is_used_if_present(self): + + app = helpers._get_test_app() + + eq_(app.flask_app.config['SECRET_KEY'], + u'super_secret_stuff') + + @helpers.change_config('SECRET_KEY', None) + def test_beaker_secret_is_used_by_default(self): + + app = helpers._get_test_app() + + eq_(app.flask_app.config['SECRET_KEY'], + config['beaker.session.secret']) + + @helpers.change_config('SECRET_KEY', None) + @helpers.change_config('beaker.session.secret', None) + def test_no_beaker_secret_crashes(self): + + assert_raises(ValueError, helpers._get_test_app) + + # TODO: When Pylons is finally removed, we should test for + # RuntimeError instead (thrown on `make_flask_stack`) diff --git a/dev-requirements.txt b/dev-requirements.txt index 095abe8a547..54503afe28e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -4,6 +4,7 @@ beautifulsoup4==4.4.1 coveralls #Let Unpinned - Requires latest coveralls docutils==0.12 factory-boy==2.1.1 +Flask-DebugToolbar==0.10.0 httpretty==0.8.3 mock==2.0.0 pep8==1.4.6