summaryrefslogtreecommitdiff
path: root/talerblog
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2018-01-16 03:21:46 +0100
committerFlorian Dold <florian.dold@gmail.com>2018-01-16 03:21:46 +0100
commitf78a9b9d30db62724978d874ce480328b295b29d (patch)
treed3a3e91377a6e6ead543bce022e0e2cbc06e8c97 /talerblog
parentba2879c71fc15c6d9e0a35da631b5b78de59f95f (diff)
downloadblog-f78a9b9d30db62724978d874ce480328b295b29d.tar.gz
blog-f78a9b9d30db62724978d874ce480328b295b29d.tar.bz2
blog-f78a9b9d30db62724978d874ce480328b295b29d.zip
proper backend error handling
Diffstat (limited to 'talerblog')
-rw-r--r--talerblog/blog/blog.py76
-rw-r--r--talerblog/blog/templates/error.html24
-rw-r--r--talerblog/helpers.py22
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