Browse Source

Exception handler for API exceptions

Rafał Pitoń 10 years ago
parent
commit
f0a1be4bed

+ 6 - 0
misago/conf/defaults.py

@@ -388,6 +388,12 @@ MISAGO_SENDFILE_LOCATIONS_PATH = ''
 CRISPY_TEMPLATE_PACK = 'bootstrap3'
 CRISPY_TEMPLATE_PACK = 'bootstrap3'
 
 
 
 
+# Rest Framework Configuration
+REST_FRAMEWORK = {
+    'EXCEPTION_HANDLER': 'misago.core.exceptionhandler.handle_api_exception'
+}
+
+
 # Register Misago debug panels
 # Register Misago debug panels
 DEBUG_TOOLBAR_PANELS = (
 DEBUG_TOOLBAR_PANELS = (
     'debug_toolbar.panels.versions.VersionsPanel',
     'debug_toolbar.panels.versions.VersionsPanel',

+ 17 - 0
misago/core/exceptionhandler.py

@@ -1,6 +1,9 @@
 from django.core.exceptions import PermissionDenied
 from django.core.exceptions import PermissionDenied
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.http import Http404, HttpResponsePermanentRedirect, JsonResponse
 from django.http import Http404, HttpResponsePermanentRedirect, JsonResponse
+from django.utils.translation import gettext as _
+
+from rest_framework.views import exception_handler as rest_exception_handler
 
 
 from misago.core import errorpages
 from misago.core import errorpages
 from misago.core.exceptions import AjaxError, ExplicitFirstPage, OutdatedSlug
 from misago.core.exceptions import AjaxError, ExplicitFirstPage, OutdatedSlug
@@ -77,3 +80,17 @@ def get_exception_handler(exception):
 def handle_misago_exception(request, exception):
 def handle_misago_exception(request, exception):
     handler = get_exception_handler(exception)
     handler = get_exception_handler(exception)
     return handler(request, exception)
     return handler(request, exception)
+
+
+def handle_api_exception(exception):
+    response = rest_exception_handler(exception)
+
+    if response:
+        if isinstance(exception, PermissionDenied):
+            try:
+                response.data['detail'] = exception.args[0]
+            except IndexError:
+                pass
+        return response
+    else:
+        return None

+ 29 - 8
misago/core/tests/test_exceptionhandler.py → misago/core/tests/test_exceptionhandlers.py

@@ -1,4 +1,6 @@
 from django.core import exceptions as django_exceptions
 from django.core import exceptions as django_exceptions
+from django.core.exceptions import PermissionDenied
+from django.http import Http404
 from django.test import TestCase
 from django.test import TestCase
 
 
 from misago.core import exceptionhandler
 from misago.core import exceptionhandler
@@ -19,10 +21,7 @@ class IsMisagoExceptionTests(TestCase):
         exceptionhandler.is_misago_exception recognizes handled exceptions
         exceptionhandler.is_misago_exception recognizes handled exceptions
         """
         """
         for exception in exceptionhandler.HANDLED_EXCEPTIONS:
         for exception in exceptionhandler.HANDLED_EXCEPTIONS:
-            try:
-                raise exception()
-            except exception as e:
-                self.assertTrue(exceptionhandler.is_misago_exception(e))
+            self.assertTrue(exceptionhandler.is_misago_exception(exception()))
 
 
     def test_is_misago_exception_false_for_not_handled_exceptions(self):
     def test_is_misago_exception_false_for_not_handled_exceptions(self):
         """
         """
@@ -30,10 +29,7 @@ class IsMisagoExceptionTests(TestCase):
         exceptions
         exceptions
         """
         """
         for exception in INVALID_EXCEPTIONS:
         for exception in INVALID_EXCEPTIONS:
-            try:
-                raise exception()
-            except exception as e:
-                self.assertFalse(exceptionhandler.is_misago_exception(e))
+            self.assertFalse(exceptionhandler.is_misago_exception(exception()))
 
 
 
 
 class GetExceptionHandlerTests(TestCase):
 class GetExceptionHandlerTests(TestCase):
@@ -52,3 +48,28 @@ class GetExceptionHandlerTests(TestCase):
         for exception in INVALID_EXCEPTIONS:
         for exception in INVALID_EXCEPTIONS:
             with self.assertRaises(ValueError):
             with self.assertRaises(ValueError):
                 exceptionhandler.get_exception_handler(exception())
                 exceptionhandler.get_exception_handler(exception())
+
+
+class HandleAPIExceptionTests(TestCase):
+    def test_permission_denied(self):
+        """permission denied exception is correctly handled"""
+        response = exceptionhandler.handle_api_exception(PermissionDenied())
+        self.assertEqual(response.status_code, 403)
+        self.assertEqual(response.data['detail'], "Permission denied")
+
+    def test_permission_message_denied(self):
+        """permission denied with message is correctly handled"""
+        exception = PermissionDenied("You shall not pass!")
+        response = exceptionhandler.handle_api_exception(exception)
+        self.assertEqual(response.status_code, 403)
+        self.assertEqual(response.data['detail'], "You shall not pass!")
+
+    def test_unhandled_exception(self):
+        """our exception handler is not interrupting other exceptions"""
+        for exception in INVALID_EXCEPTIONS:
+            response = exceptionhandler.handle_api_exception(exception())
+            self.assertIsNone(response)
+
+        response = exceptionhandler.handle_api_exception(Http404())
+        self.assertEqual(response.status_code, 404)
+        self.assertEqual(response.data['detail'], "Not found")