about summary refs log tree commit diff
path: root/uploader
diff options
context:
space:
mode:
Diffstat (limited to 'uploader')
-rw-r--r--uploader/monadic_requests.py48
-rw-r--r--uploader/oauth2/views.py12
-rw-r--r--uploader/templates/unhandled_exception.html25
3 files changed, 67 insertions, 18 deletions
diff --git a/uploader/monadic_requests.py b/uploader/monadic_requests.py
index f0a60f4..aa34951 100644
--- a/uploader/monadic_requests.py
+++ b/uploader/monadic_requests.py
@@ -1,9 +1,57 @@
 """Wrap requests functions with monads."""
+import traceback
+from typing import Union, Optional, Callable
+
 import requests
+from requests.models import Response
 from pymonad.either import Left, Right, Either
+from flask import (
+    flash,
+    request,
+    redirect,
+    render_template,
+    current_app as app,
+    escape as flask_escape)
 
+# HTML Status codes indicating a successful request.
 SUCCESS_CODES = (200, 201, 202, 203, 204, 205, 206, 207, 208, 226)
 
+# Possible error(s) that can be encontered while attempting to do a request.
+PossibleError = Union[Response, Exception]
+
+
+def make_error_handler(
+        redirect_to: Optional[Response] = None,
+        cleanup_thunk: Callable = lambda *args: None
+) -> Callable[[PossibleError], Response]:
+    """
+    Build a function to gracefully handle errors encountered while doing
+    requests.
+
+    :rtype: Callable
+    """
+    redirect_to = redirect_to or redirect(request.url)
+    def __handler__(resp_or_exc: PossibleError) -> Response:
+        cleanup_thunk()
+        if issubclass(type(resp_or_exc), Exception):
+            # Is an exception!
+            return render_template(
+                "unhandled_exception.html",
+                trace=traceback.format_exception(resp_or_exc))
+        if isinstance(resp_or_exc, Response):
+            flash("The authorisation server responded with "
+                  f"({flask_escape(resp_or_exc.status_code)}, "
+                  f"{flask_escape(resp_or_exc.reason)}) for the request to "
+                  f"'{flask_escape(resp_or_exc.request.url)}'",
+                  "alert-danger")
+            return redirect_to
+
+        flash("Unspecified error!", "alert-danger")
+        app.logger.debug("Error (%s): %s", type(resp_or_exc), resp_or_exc)
+        return redirect_to
+    return __handler__
+
+
 def get(url, params=None, **kwargs) -> Either:
     """
     A wrapper around `requests.get` function.
diff --git a/uploader/oauth2/views.py b/uploader/oauth2/views.py
index d196e22..40211c8 100644
--- a/uploader/oauth2/views.py
+++ b/uploader/oauth2/views.py
@@ -15,6 +15,7 @@ from flask import (
 
 from uploader import session
 from uploader import monadic_requests as mrequests
+from uploader.monadic_requests import make_error_handler
 
 from . import jwks
 from .client import (
@@ -118,12 +119,6 @@ def logout():
         flash("Successfully logged out.", "alert-success")
         return redirect("/")
 
-    def __handle_failure__(_failure):
-        app.logger.debug("There was a failure logging out of the system",
-                         exc_info=True, stack_info=True)
-        __unset_session__(session.session_info())
-        return redirect("/")
-
     if user_logged_in():
         return session.user_token().then(
             lambda _tok: mrequests.post(
@@ -133,5 +128,8 @@ def logout():
                     "client_id": oauth2_clientid(),
                     "client_secret": oauth2_clientsecret()
                 })).either(
-                    __handle_failure__,
+                    make_error_handler(
+                        redirect_to=redirect("/"),
+                        cleanup_thunk=lambda: __unset_session__(
+                            session.session_info())),
                     lambda res: __unset_session__(session.session_info()))
diff --git a/uploader/templates/unhandled_exception.html b/uploader/templates/unhandled_exception.html
index 6e6a051..d6087cb 100644
--- a/uploader/templates/unhandled_exception.html
+++ b/uploader/templates/unhandled_exception.html
@@ -1,4 +1,5 @@
 {%extends "base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
 
 {%block title%}System Error{%endblock%}
 
@@ -7,15 +8,17 @@
 {%endblock%}
 
 {%block contents%}
-<p>
-  An error has occured, and your request has been aborted. Please notify the
-  administrator to try and get this sorted.
-</p>
-<p>
-  Provide the following information to help the administrator figure out and fix
-  the issue:<br />
-  <hr /><br />
-  {{trace}}
-  <hr /><br />
-</p>
+<div class="row">
+  {{flash_all_messages()}}
+  <h1>Exception!</h1>
+
+  <p>An error has occured, and your request has been aborted. Please notify the
+    administrator to try and get this fixed.</p>
+  <p>The system has failed with the following error:</p>
+</div>
+<div class="row">
+  <pre>
+    {{'\n'.join(trace).strip()}}
+  </pre>
+</div>
 {%endblock%}