summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--talersurvey/survey/amount.py135
-rw-r--r--talersurvey/survey/survey.py66
-rw-r--r--talersurvey/survey/templates/base.html10
-rw-r--r--talersurvey/survey/templates/index.html2
4 files changed, 38 insertions, 175 deletions
diff --git a/talersurvey/survey/amount.py b/talersurvey/survey/amount.py
deleted file mode 100644
index 46e3446..0000000
--- a/talersurvey/survey/amount.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# This file is part of TALER
-# (C) 2017 TALER SYSTEMS
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-# @author Marcello Stanisci
-# @version 0.1
-# @repository https://git.taler.net/copylib.git/
-# This code is "copylib", it is versioned under the Git repository
-# mentioned above, and it is meant to be manually copied into any project
-# which might need it.
-
-class CurrencyMismatch(Exception):
- def __init__(self, curr1, curr2):
- super(CurrencyMismatch, self).__init__(
- "%s vs %s" % (curr1, curr2))
-
-class BadFormatAmount(Exception):
- def __init__(self, faulty_str):
- super(BadFormatAmount, self).__init__(
- "Bad format amount: " + faulty_str)
-
-class Amount:
- # How many "fraction" units make one "value" unit of currency
- # (Taler requires 10^8). Do not change this 'constant'.
- @staticmethod
- def _fraction():
- return 10 ** 8
-
- @staticmethod
- def _max_value():
- return (2 ** 53) - 1
-
- def __init__(self, currency, value=0, fraction=0):
- # type: (str, int, int) -> Amount
- assert value >= 0 and fraction >= 0
- self.value = value
- self.fraction = fraction
- self.currency = currency
- self.__normalize()
- assert self.value <= Amount._max_value()
-
- # Normalize amount
- def __normalize(self):
- if self.fraction >= Amount._fraction():
- self.value += int(self.fraction / Amount._fraction())
- self.fraction = self.fraction % Amount._fraction()
-
- # Parse a string matching the format "A:B.C"
- # instantiating an amount object.
- @classmethod
- def parse(cls, amount_str):
- exp = r'^\s*([-_*A-Za-z0-9]+):([0-9]+)\.([0-9]+)\s*$'
- import re
- parsed = re.search(exp, amount_str)
- if not parsed:
- raise BadFormatAmount(amount_str)
- value = int(parsed.group(2))
- fraction = 0
- for i, digit in enumerate(parsed.group(3)):
- fraction += int(int(digit) * (Amount._fraction() / 10 ** (i+1)))
- return cls(parsed.group(1), value, fraction)
-
- # Comare two amounts, return:
- # -1 if a < b
- # 0 if a == b
- # 1 if a > b
- @staticmethod
- def cmp(am1, am2):
- if am1.currency != am2.currency:
- raise CurrencyMismatch(am1.currency, am2.currency)
- if am1.value == am2.value:
- if am1.fraction < am2.fraction:
- return -1
- if am1.fraction > am2.fraction:
- return 1
- return 0
- if am1.value < am2.value:
- return -1
- return 1
-
- def set(self, currency, value=0, fraction=0):
- self.currency = currency
- self.value = value
- self.fraction = fraction
-
- # Add the given amount to this one
- def add(self, amount):
- if self.currency != amount.currency:
- raise CurrencyMismatch(self.currency, amount.currency)
- self.value += amount.value
- self.fraction += amount.fraction
- self.__normalize()
-
- # Subtract passed amount from this one
- def subtract(self, amount):
- if self.currency != amount.currency:
- raise CurrencyMismatch(self.currency, amount.currency)
- if self.fraction < amount.fraction:
- self.fraction += Amount._fraction()
- self.value -= 1
- if self.value < amount.value:
- raise ValueError('self is lesser than amount to be subtracted')
- self.value -= amount.value
- self.fraction -= amount.fraction
-
- # Dump string from this amount, will put 'ndigits' numbers
- # after the dot.
- def stringify(self, ndigits):
- assert ndigits > 0
- ret = '%s:%s.' % (self.currency, str(self.value))
- fraction = self.fraction
- while ndigits > 0:
- ret += str(int(fraction / (Amount._fraction() / 10)))
- fraction = (fraction * 10) % (Amount._fraction())
- ndigits -= 1
- return ret
-
- # Dump the Taler-compliant 'dict' amount
- def dump(self):
- return dict(value=self.value,
- fraction=self.fraction,
- currency=self.currency)
diff --git a/talersurvey/survey/survey.py b/talersurvey/survey/survey.py
index 6c2f4c8..d068f66 100644
--- a/talersurvey/survey/survey.py
+++ b/talersurvey/survey/survey.py
@@ -48,55 +48,53 @@ def backend_error(requests_response):
@app.context_processor
def utility_processor():
-
- def join_urlparts(*parts):
- ret = ""
- part = 0
- while part < len(parts):
- buf = parts[part]
- part += 1
- if ret.endswith("/"):
- buf = buf.lstrip("/")
- elif ret and not buf.startswith("/"):
- buf = "/" + buf
- ret += buf
- return ret
-
- def url(my_url):
- return join_urlparts(flask.request.script_root, my_url)
def env(name, default=None):
return os.environ.get(name, default)
return dict(url=url, env=env)
-@app.route("/tip-pickup", methods=["POST"])
-def pick():
- request_body = flask.request.get_json()
- resp = requests.post(urljoin(BACKEND_URL, "tip-pickup"),
- json=request_body)
+def err_abort(abort_status_code, **params):
+ t = flask.render_template("templates/error.html", **params)
+ flask.abort(flask.make_response(t, abort_status_code))
+
+
+def backend_post(endpoint, json):
+ try:
+ resp = requests.post(urljoin(BACKEND_URL, endpoint), json=json)
+ except requests.ConnectionError:
+ err_abort(500, message="Could not establish connection to backend")
+ try:
+ response_json = resp.json()
+ except ValueError:
+ err_abort(500, message="Could not parse response from backend",
+ status_code=resp.status_code)
if resp.status_code != 200:
- return backend_error(resp)
- response_body = resp.json()
- return flask.jsonify(response_body)
+ err_abort(500, 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("/submit-survey", methods=["POST"])
def submit_survey():
tip_spec = dict(pickup_url=urljoin(flask.request.base_url, "/tip-pickup"),
- amount=Amount(CURRENCY, 1).dump(),
+ amount=CURRENCY + ":1.0",
next_url=os.environ.get("TALER_ENV_URL_INTRO", "https://taler.net/"),
instance="default",
justification="Payment methods survey")
- resp = requests.post(urljoin(BACKEND_URL, "tip-authorize"),
- json=tip_spec)
- if resp.status_code != 200:
- return backend_error(resp)
+ resp = backend_post("tip-authorize", tip_spec)
- response = flask.make_response(
- flask.render_template("templates/wait.html", success=True),
- 402)
- response.headers["X-Taler-Tip"] = resp.json()["tip_token"]
+ if resp.get("tip_redirect_url"):
+ flask.redirect(resp["tip_redirect_url"]
- return response
+ err_abort(500, message="Tipping failed, unexpected backend response",
+ json=resp)
@app.route("/", methods=["GET"])
diff --git a/talersurvey/survey/templates/base.html b/talersurvey/survey/templates/base.html
index 5dbf182..e5cf03c 100644
--- a/talersurvey/survey/templates/base.html
+++ b/talersurvey/survey/templates/base.html
@@ -18,10 +18,10 @@
<html>
<head>
<title>Taler Survey Demo</title>
- <link rel="stylesheet" type="text/css" href="{{ url('/static/web-common/pure.css') }}" />
- <link rel="stylesheet" type="text/css" href="{{ url('/static/web-common/demo.css') }}" />
- <script src="{{ url("/static/web-common/taler-wallet-lib.js") }}" type="application/javascript"></script>
- <script src="{{ url("/static/web-common/lang.js") }}" type="application/javascript"></script>
+ <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='web-common/pure.css') }}" />
+ <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='web-common/demo.css') }}" />
+ <script src="{{ url_for('static', filename='web-common/taler-wallet-lib.js') }}" type="application/javascript"></script>
+ <script src="{{ url_for('static', filename='static/web-common/lang.js') }}" type="application/javascript"></script>
{% block styles %}{% endblock %}
{% block scripts %}{% endblock %}
</head>
@@ -42,7 +42,7 @@
</div>
<section id="main" class="content">
- <a href="{{ url("/") }}">
+ <a href="{{ url_for('index') }}">
<div id="logo">
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="darkcyan" stroke-width="6" fill="white" />
diff --git a/talersurvey/survey/templates/index.html b/talersurvey/survey/templates/index.html
index 1799abd..f40c235 100644
--- a/talersurvey/survey/templates/index.html
+++ b/talersurvey/survey/templates/index.html
@@ -8,7 +8,7 @@
</p>
</div>
<div>
- <form action="{{ url('/submit-survey') }}" method="post" class="pure-form pure-form-stacked">
+ <form action="{{ url_for('submit_survey') }}" method="post" class="pure-form pure-form-stacked">
<legend>What do you prefer?</legend>
<fieldset>
<label for="option-taler">