db: [{{ db }}]
diff --git a/caravel/templates/caravel/welcome.html b/caravel/templates/caravel/welcome.html
index 362b1af15..31443f1e9 100644
--- a/caravel/templates/caravel/welcome.html
+++ b/caravel/templates/caravel/welcome.html
@@ -9,6 +9,7 @@
{% block body %}
+ {% include 'caravel/flash_wrapper.html' %}
diff --git a/caravel/views.py b/caravel/views.py
index 6dc410f27..17d492926 100644
--- a/caravel/views.py
+++ b/caravel/views.py
@@ -12,6 +12,7 @@ import time
import traceback
from datetime import datetime
+import functools
import pandas as pd
import sqlalchemy as sqla
@@ -20,7 +21,7 @@ from flask import (
from flask_appbuilder import ModelView, CompactCRUDMixin, BaseView, expose
from flask_appbuilder.actions import action
from flask_appbuilder.models.sqla.interface import SQLAInterface
-from flask_appbuilder.security.decorators import has_access
+from flask_appbuilder.security.decorators import has_access, has_access_api
from flask_babelpkg import gettext as __
from flask_babelpkg import lazy_gettext as _
from flask_appbuilder.models.sqla.filters import BaseFilter
@@ -37,6 +38,38 @@ config = app.config
log_this = models.Log.log_this
+def get_error_msg():
+ if config.get("SHOW_STACKTRACE"):
+ error_msg = traceback.format_exc()
+ else:
+ error_msg = "FATAL ERROR \n"
+ error_msg += (
+ "Stacktrace is hidden. Change the SHOW_STACKTRACE "
+ "configuration setting to enable it")
+ return error_msg
+
+
+def api(f):
+ """
+ A decorator to label an endpoint as an API. Catches uncaught exceptions and
+ return the response in the JSON format
+ """
+ def wraps(self, *args, **kwargs):
+ try:
+ return f(self, *args, **kwargs)
+ except Exception as e:
+ logging.exception(e)
+ resp = Response(
+ json.dumps({
+ 'message': get_error_msg()
+ }),
+ status=500,
+ mimetype="application/json")
+ return resp
+
+ return functools.update_wrapper(wraps, f)
+
+
def check_ownership(obj, raise_if_false=True):
"""Meant to be used in `pre_update` hooks on models to enforce ownership
@@ -861,7 +894,8 @@ class Caravel(BaseView):
msg = "Slice [{}] has been overwritten".format(slc.slice_name)
flash(msg, "info")
- @has_access
+ @api
+ @has_access_api
@expose("/checkbox/
///", methods=['GET'])
def checkbox(self, model_view, id_, attr, value):
"""endpoint for checking/unchecking any boolean in a sqla model"""
@@ -875,7 +909,8 @@ class Caravel(BaseView):
db.session.commit()
return Response("OK", mimetype="application/json")
- @has_access
+ @api
+ @has_access_api
@expose("/activity_per_day")
def activity_per_day(self):
"""endpoint to power the calendar heatmap on the welcome page"""
@@ -891,7 +926,8 @@ class Caravel(BaseView):
payload = {str(time.mktime(dt.timetuple())): ccount for dt, ccount in qry if dt}
return Response(json.dumps(payload), mimetype="application/json")
- @has_access
+ @api
+ @has_access_api
@expose("/save_dash//", methods=['GET', 'POST'])
def save_dash(self, dashboard_id):
"""Save a dashboard's metadata"""
@@ -915,7 +951,8 @@ class Caravel(BaseView):
session.close()
return "SUCCESS"
- @has_access
+ @api
+ @has_access_api
@expose("/testconn", methods=["POST", "GET"])
def testconn(self):
"""Tests a sqla connection"""
@@ -1121,13 +1158,7 @@ class Caravel(BaseView):
@app.errorhandler(500)
def show_traceback(self):
- if config.get("SHOW_STACKTRACE"):
- error_msg = traceback.format_exc()
- else:
- error_msg = "FATAL ERROR\n"
- error_msg = (
- "Stacktrace is hidden. Change the SHOW_STACKTRACE "
- "configuration setting to enable it")
+ error_msg = get_error_msg()
return render_template(
'caravel/traceback.html',
error_msg=error_msg,
diff --git a/tests/core_tests.py b/tests/core_tests.py
index 6470fbcaf..598b7d6e0 100644
--- a/tests/core_tests.py
+++ b/tests/core_tests.py
@@ -258,7 +258,7 @@ class CoreTests(CaravelTestCase):
self.logout()
self.assertRaises(
- utils.CaravelSecurityException, self.test_save_dash, 'alpha')
+ AssertionError, self.test_save_dash, 'alpha')
alpha = appbuilder.sm.find_user('alpha')