diff options
author | Frederick Muriuki Muriithi | 2024-07-29 16:04:13 -0500 |
---|---|---|
committer | Frederick Muriuki Muriithi | 2024-08-05 09:52:18 -0500 |
commit | e16d7750c9f1e754a3e14a496380de0b014fffe1 (patch) | |
tree | c24e12b1381cd61363febfc5bcde165bd8fd0a46 | |
parent | d3fd64fb5237febb9628c4ccbd259969327ab2ec (diff) | |
download | gn-uploader-e16d7750c9f1e754a3e14a496380de0b014fffe1.tar.gz |
Provide a generalised way to handle errors and exceptions.
-rw-r--r-- | uploader/monadic_requests.py | 48 | ||||
-rw-r--r-- | uploader/oauth2/views.py | 12 | ||||
-rw-r--r-- | uploader/templates/unhandled_exception.html | 25 |
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%} |