From 596cf4f7c558276c1edd02b99d432ecf0c82c0a0 Mon Sep 17 00:00:00 2001 From: Alice Heaton <aliceh@aptivate.org> Date: Thu, 23 Jul 2015 16:17:27 +0100 Subject: [PATCH] Ensure dashboard displays error in case of missing or faulty widget, rather than causing the whole application to fail. --- .../templates/dashboard/widget-error.html | 10 +++++ .../dashboard/widget-missing-template.html | 1 - .../dashboard/templatetags/render_widget.py | 42 +++++++++++++++---- django/website/dashboard/views.py | 7 +++- django/website/dashboard/widget_pool.py | 12 +++++- .../widgets/{chart.py => term_count_chart.py} | 0 6 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 django/website/dashboard/templates/dashboard/widget-error.html delete mode 100644 django/website/dashboard/templates/dashboard/widget-missing-template.html rename django/website/hid/widgets/{chart.py => term_count_chart.py} (100%) diff --git a/django/website/dashboard/templates/dashboard/widget-error.html b/django/website/dashboard/templates/dashboard/widget-error.html new file mode 100644 index 00000000..38d75f8d --- /dev/null +++ b/django/website/dashboard/templates/dashboard/widget-error.html @@ -0,0 +1,10 @@ +{% load i18n %} +<div class='panel panel-default'> + <div class='panel-heading'> + <span class='fa fa-warning fa-fw'></span> + <h2>{% trans "Error" %}</h2> + </div> + <div class='panel-body'> + {{ error }} + </div> +</div> diff --git a/django/website/dashboard/templates/dashboard/widget-missing-template.html b/django/website/dashboard/templates/dashboard/widget-missing-template.html deleted file mode 100644 index 3f976032..00000000 --- a/django/website/dashboard/templates/dashboard/widget-missing-template.html +++ /dev/null @@ -1 +0,0 @@ -Missing template_name for widget type {{empty_type}} diff --git a/django/website/dashboard/templatetags/render_widget.py b/django/website/dashboard/templatetags/render_widget.py index d090438b..904b0a61 100644 --- a/django/website/dashboard/templatetags/render_widget.py +++ b/django/website/dashboard/templatetags/render_widget.py @@ -1,9 +1,13 @@ +import logging + from django import template from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ -from dashboard.widget_pool import get_widget +from dashboard.widget_pool import get_widget, MissingWidgetType +logger = logging.getLogger(__name__) register = template.Library() @@ -16,18 +20,40 @@ def render_widget(widget_instance): get_context_data then that is used to generate the template context. """ - widget = get_widget(widget_instance.widget_type) + widget = None + # Get settings, if any if widget_instance.settings: settings = widget_instance.settings else: settings = {} + # Get widget try: - context = widget.get_context_data(**settings) - except AttributeError: + widget = get_widget(widget_instance.widget_type) + except MissingWidgetType: + template_name = 'dashboard/widget-error.html' context = {} - try: - template_name = widget.template_name - except AttributeError: - template_name = 'dashboard/widget-missing-template.html' + context['error'] = _('Unknown widget type %(widget_type)s') % { + 'widget_type': widget_instance.widget_type + } context['empty_type'] = widget_instance.widget_type + if widget: + # Get template + try: + template_name = widget.template_name + except AttributeError: + template_name = 'dashboard/widget-error.html' + context = {} + context['error'] = _('Missing template for %(widget_type)s') % { + 'widget_type': widget_instance.widget_type + } + widget = None + if widget: + # Get context + try: + context = widget.get_context_data(**settings) + except: + logger.exception() + template_name = 'dashboard/widget-error.html' + context['error'] = _('Widget error. See error logs.') + return render_to_string(template_name, context) diff --git a/django/website/dashboard/views.py b/django/website/dashboard/views.py index 73f4a3b6..b20136dc 100644 --- a/django/website/dashboard/views.py +++ b/django/website/dashboard/views.py @@ -3,7 +3,7 @@ from django.views.generic import TemplateView from hid.assets import require_assets from dashboard.models import Dashboard -from dashboard.widget_pool import get_widget +from dashboard.widget_pool import get_widget, MissingWidgetType class DashboardView(TemplateView): @@ -43,7 +43,10 @@ class DashboardView(TemplateView): # Ensure we have all the javascript & css dependencies require_assets('dashboard/dashboard.css') for widget in widgets: - widget_type = get_widget(widget.widget_type) + try: + widget_type = get_widget(widget.widget_type) + except MissingWidgetType: + continue if hasattr(widget_type, 'javascript'): require_assets(*widget_type.javascript) if hasattr(widget_type, 'css'): diff --git a/django/website/dashboard/widget_pool.py b/django/website/dashboard/widget_pool.py index 7615b0bb..98cc08bc 100644 --- a/django/website/dashboard/widget_pool.py +++ b/django/website/dashboard/widget_pool.py @@ -1,6 +1,11 @@ _pool = {} +class MissingWidgetType(Exception): + """ Exception raised when a widget type is missing """ + pass + + def register_widget(name, widget): """ Register a new widget type @@ -24,10 +29,13 @@ def get_widget(name): Returns: The widget object as registered with register_widget Raises: - KeyError: If the widget type does not exist + MissingWidgetType: If the widget type does not exist """ global _pool - return _pool[name] + try: + return _pool[name] + except KeyError: + raise MissingWidgetType() class BasicTextWidget(object): diff --git a/django/website/hid/widgets/chart.py b/django/website/hid/widgets/term_count_chart.py similarity index 100% rename from django/website/hid/widgets/chart.py rename to django/website/hid/widgets/term_count_chart.py -- GitLab