aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-07-29 16:04:13 -0500
committerFrederick Muriuki Muriithi2024-08-05 09:52:18 -0500
commite16d7750c9f1e754a3e14a496380de0b014fffe1 (patch)
treec24e12b1381cd61363febfc5bcde165bd8fd0a46
parentd3fd64fb5237febb9628c4ccbd259969327ab2ec (diff)
downloadgn-uploader-e16d7750c9f1e754a3e14a496380de0b014fffe1.tar.gz
Provide a generalised way to handle errors and exceptions.
-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%}