diff --git a/common/djangoapps/util/views.py b/common/djangoapps/util/views.py index 5ac26f781935a2d9998be5179b8de6cba56ec950..74b9d799ccae979b3f887c30de391808411b489a 100644 --- a/common/djangoapps/util/views.py +++ b/common/djangoapps/util/views.py @@ -56,6 +56,39 @@ def jsonable_server_error(request, template_name='500.html'): return server_error(request, template_name=template_name) +def handle_500(template_path, context=None): + """ + Decorator for view specific 500 error handling. + + Usage:: + + @handle_500(template_path='certificates/server-error.html', context={'error-info': 'Internal Server Error'}) + def my_view(request): + # Any unhandled exception in this view would be handled by the handle_500 decorator + # ... + + """ + def decorator(func): + """ + Decorator to render custom html template in case of uncaught exception in wrapped function + """ + @wraps(func) + def inner(request, *args, **kwargs): + """ + Execute the function in try..except block and return custom server-error page in case of unhandled exception + """ + try: + return func(request, *args, **kwargs) + except Exception: # pylint: disable=broad-except + if settings.DEBUG: + # In debug mode let django process the 500 errors and display debug info for the developer + raise + else: + return render_to_response(template_path, context) + return inner + return decorator + + def calculate(request): ''' Calculator in footer of every page. ''' equation = request.GET['equation'] diff --git a/lms/djangoapps/certificates/tests/test_webview_views.py b/lms/djangoapps/certificates/tests/test_webview_views.py index 8e4e4d2577aaf217d4b7f9322af79d5a23e83fbc..0e52758b72846bfcb4552aa3878ca78481148858 100644 --- a/lms/djangoapps/certificates/tests/test_webview_views.py +++ b/lms/djangoapps/certificates/tests/test_webview_views.py @@ -24,6 +24,7 @@ from certificates.models import ( CertificateStatuses, CertificateSocialNetworks, CertificateTemplate, + CertificateHtmlViewConfiguration ) from certificates.tests.factories import ( @@ -417,6 +418,17 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): response = self.client.get(test_url) self.assertIn("Invalid Certificate", response.content) + @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) + def test_render_500_view_invalid_certificate_configuration(self): + CertificateHtmlViewConfiguration.objects.all().update(enabled=False) + + test_url = get_certificate_url( + user_id=self.user.id, + course_id=unicode(self.course.id) + ) + response = self.client.get(test_url) + self.assertIn("Invalid Certificate Configuration", response.content) + @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) def test_certificate_evidence_event_emitted(self): self.client.logout() diff --git a/lms/djangoapps/certificates/views/webview.py b/lms/djangoapps/certificates/views/webview.py index 801ba3557c5b6314000ddbd9de85b6fc46c68c40..6377648d82e7e35633bf91d004fff2a33b0ed9fc 100644 --- a/lms/djangoapps/certificates/views/webview.py +++ b/lms/djangoapps/certificates/views/webview.py @@ -23,6 +23,7 @@ from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from student.models import LinkedInAddToProfileConfiguration from util import organizations_helpers as organization_api +from util.views import handle_500 from xmodule.modulestore.django import modulestore from certificates.api import ( @@ -279,6 +280,7 @@ def _update_certificate_context(context, course, user, user_certificate): ) +@handle_500(template_path="certificates/server-error.html") def render_html_view(request, user_id, course_id): """ This public view generates an HTML representation of the specified student's certificate diff --git a/lms/templates/certificates/server-error.html b/lms/templates/certificates/server-error.html new file mode 100644 index 0000000000000000000000000000000000000000..89a949a843453fb0707960bb890e1423ff2d2eeb --- /dev/null +++ b/lms/templates/certificates/server-error.html @@ -0,0 +1,25 @@ +<%! from django.utils.translation import ugettext as _ %> +<%inherit file="../main.html" /> + +<%block name="pagetitle">${_("Invalid Certificate Configuration.")}</%block> + +<section class="outside-app"> + <h1> + ${_(u"There is a problem with this certificate on {platform_name}".format( + platform_name=u"<em>{platform_name}</em>".format(platform_name=settings.PLATFORM_NAME)))} + </h1> + + <div> + <p> + ${_("To resolve the problem, your partner manager should verify that the following information is correct.")} + </p> + <ul> + <li>${_("The institution's logo.")}</li> + <li>${_("The institution that is linked to the course.")}</li> + <li>${_("The course information in the Course Administration tool.")}</li> + </ul> + <br/> + <p>${_("If all of the information is correct and the problem persists, contact technical support.")}</p> + </div> + +</section>