diff options
author | Florian Dold <florian.dold@gmail.com> | 2018-01-16 03:21:46 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2018-01-16 03:21:46 +0100 |
commit | f78a9b9d30db62724978d874ce480328b295b29d (patch) | |
tree | d3a3e91377a6e6ead543bce022e0e2cbc06e8c97 /talerblog | |
parent | ba2879c71fc15c6d9e0a35da631b5b78de59f95f (diff) | |
download | blog-f78a9b9d30db62724978d874ce480328b295b29d.tar.gz blog-f78a9b9d30db62724978d874ce480328b295b29d.tar.bz2 blog-f78a9b9d30db62724978d874ce480328b295b29d.zip |
proper backend error handling
Diffstat (limited to 'talerblog')
-rw-r--r-- | talerblog/blog/blog.py | 76 | ||||
-rw-r--r-- | talerblog/blog/templates/error.html | 24 | ||||
-rw-r--r-- | talerblog/helpers.py | 22 |
3 files changed, 78 insertions, 44 deletions
diff --git a/talerblog/blog/blog.py b/talerblog/blog/blog.py index c11fe3d..0272442 100644 --- a/talerblog/blog/blog.py +++ b/talerblog/blog/blog.py @@ -20,24 +20,21 @@ Implement URL handlers and payment logic for the blog merchant. """ -from urllib.parse import urljoin, quote, parse_qsl +from urllib.parse import urljoin, quote import logging import os +import traceback import uuid import base64 import requests import flask from talerblog.talerconfig import TalerConfig -from ..helpers import (make_url, \ - expect_parameter, join_urlparts, \ - get_query_string, backend_error) -from ..blog.content import (ARTICLES, \ - get_article_file, get_image_file) +from ..helpers import make_url, join_urlparts +from ..blog.content import ARTICLES, get_article_file, get_image_file BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = flask.Flask(__name__, template_folder=BASE_DIR) -app.debug = True app.secret_key = base64.b64encode(os.urandom(64)).decode('utf-8') LOGGER = logging.getLogger(__name__) @@ -52,6 +49,7 @@ app.config.from_object(__name__) @app.context_processor def utility_processor(): + # These helpers will be available in templates def url(my_url): return join_urlparts(flask.request.script_root, my_url) def env(name, default=None): @@ -59,6 +57,49 @@ def utility_processor(): return dict(url=url, env=env) +def err_abort(**params): + t = flask.render_template("templates/error.html", **params) + flask.abort(flask.make_response(t)) + + +def backend_get(endpoint, params): + try: + resp = requests.get(urljoin(BACKEND_URL, endpoint), params=params) + except requests.ConnectionError: + err_abort(message="Could not establish connection to backend") + try: + response_json = resp.json() + except ValueError: + err_abort(message="Could not parse response from backend") + if resp.status_code != 200: + err_abort(message="Backend returned error status", + json=response_json, status_code=resp.status_code) + return response_json + + +def backend_post(endpoint, json): + try: + resp = requests.post(urljoin(BACKEND_URL, endpoint), json=json) + except requests.ConnectionError: + err_abort(message="Could not establish connection to backend") + try: + response_json = resp.json() + except ValueError: + err_abort(message="Could not parse response from backend", + status_code=resp.status_code) + if resp.status_code != 200: + err_abort(message="Backend returned error status", + json=response_json, status_code=resp.status_code) + return response_json + + +@app.errorhandler(Exception) +def internal_error(e) + return flask.render_template("templates/error.html", + message="Internal error", + stack=traceback.format_exc()) + + @app.route("/") def index(): return flask.render_template("templates/index.html", @@ -82,14 +123,12 @@ def refund(): order_id = payed_articles.get(article_name) if not order_id: return flask.jsonify(dict(error="Aborting refund: article not payed")), 401 - resp = requests.post(urljoin(BACKEND_URL, "refund"), + resp = backend_post(urljoin(BACKEND_URL, "refund"), json=dict(order_id=order_id, refund=ARTICLE_AMOUNT, reason="Demo reimbursement", instance=INSTANCE)) - if resp.status_code != 200: - return backend_error(resp) - if pay_status.get("refund_redirect_url"): + if resp.get("refund_redirect_url"): return flask.redirect(pay_status["refund_redirect_url"]) flask.abort(500) @@ -115,11 +154,7 @@ def article(article_name, data=None): amount=ARTICLE_AMOUNT, instance=INSTANCE, ) - resp = requests.post(urljoin(BACKEND_URL, "proposal"), - json=dict(order=order)) - if resp.status_code != 200: - return backend_error(resp) - proposal_resp = resp.json() + proposal_resp = backend_post("proposal", dict(order=order)) order_id = proposal_resp["order_id"] session_sig = flask.request.args.get("session_id") @@ -136,17 +171,14 @@ def article(article_name, data=None): session_sig=session_sig, ) - resp = requests.get(urljoin(BACKEND_URL, "check-payment"), params=pay_params) - if resp.status_code != 200: - return backend_error(resp) - - pay_status = resp.json() + pay_status = backend_get("check-payment", pay_params) if pay_status.get("payment_redirect_url"): return flask.redirect(pay_status["payment_redirect_url"]) if pay_status.get("refunded"): - return flask.render_template("templates/article_refunded.html", article_name=article_name) + return flask.render_template("templates/article_refunded.html", + article_name=article_name) if pay_status.get("paid"): article_info = ARTICLES.get(article_name) diff --git a/talerblog/blog/templates/error.html b/talerblog/blog/templates/error.html new file mode 100644 index 0000000..016321b --- /dev/null +++ b/talerblog/blog/templates/error.html @@ -0,0 +1,24 @@ +{% extends "templates/base.html" %} +{% block main %} + <h1>An Error Occored</h1> + + <p>{{ message }}</p> + + {% if status_code %} + <p>The backend returned status code {{ status_code }}.</p> + {% endif %} + + {% if json %} + <p>Backend Response:</p> + <pre> + {{ json }} + </pre> + {% endif %} + + {% if stack %} + <p>Stack trace:</p> + <pre> + {{ stack }} + </pre> + {% endif %} +{% endblock main %} diff --git a/talerblog/helpers.py b/talerblog/helpers.py index 614e463..83eccd5 100644 --- a/talerblog/helpers.py +++ b/talerblog/helpers.py @@ -77,25 +77,3 @@ def make_url(page, *query_params): # urlencode is overly eager with quoting, the wallet right now # needs some characters unquoted. return url.replace("%24", "$").replace("%7B", "{").replace("%7D", "}") - - -def expect_parameter(name, alt=None): - value = flask.request.args.get(name, None) - if value is None and alt is None: - LOGGER.error("Missing parameter '%s' from '%s'." % (name, flask.request.args)) - raise MissingParameterException(name) - return value if value else alt - - -def get_query_string(): - return flask.request.query_string - -def backend_error(requests_response): - LOGGER.error("Backend error: status code: " - + str(requests_response.status_code)) - try: - return flask.jsonify(requests_response.json()), requests_response.status_code - except json.decoder.JSONDecodeError: - LOGGER.error("Backend error (NO JSON returned): status code: " - + str(requests_response.status_code)) - return flask.jsonify(dict(error="Backend died, no JSON got from it")), 502 |