summaryrefslogtreecommitdiff
path: root/talersurvey
diff options
context:
space:
mode:
Diffstat (limited to 'talersurvey')
-rw-r--r--talersurvey/survey/survey.py127
-rw-r--r--talersurvey/survey/templates/index.html6
-rw-r--r--talersurvey/survey/templates/show_tip.html35
-rw-r--r--talersurvey/tests.py1
4 files changed, 127 insertions, 42 deletions
diff --git a/talersurvey/survey/survey.py b/talersurvey/survey/survey.py
index 897c4bf..a016a9f 100644
--- a/talersurvey/survey/survey.py
+++ b/talersurvey/survey/survey.py
@@ -26,6 +26,9 @@ from urllib.parse import urljoin
import flask
import requests
import traceback
+import qrcode
+import qrcode.image.svg
+import lxml.etree
from taler.util.talerconfig import TalerConfig
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -48,14 +51,21 @@ LOGGER = logging.getLogger(__name__)
# the merchant backend.
# @return a flask-native response object.
def backend_error(requests_response):
- LOGGER.error("Backend error: status code: "
- + str(requests_response.status_code))
+ LOGGER.error(
+ "Backend error: status code: " + str(requests_response.status_code)
+ )
try:
- return flask.jsonify(requests_response.json()), requests_response.status_code
+ 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
+ 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
##
@@ -66,14 +76,15 @@ def backend_error(requests_response):
def utility_processor():
def env(name, default=None):
return os.environ.get(name, default)
+
def prettydate(talerdate):
- parsed_time = re.search(r"/Date\(([0-9]+)\)/", talerdate)
- if not parsed_time:
- return "malformed date given"
- parsed_time = int(parsed_time.group(1))
- timestamp = datetime.datetime.fromtimestamp(parsed_time)
- # returns the YYYY-MM-DD date format.
- return timestamp.strftime("%Y-%b-%d")
+ parsed_time = re.search(r"/Date\(([0-9]+)\)/", talerdate)
+ if not parsed_time:
+ return "malformed date given"
+ parsed_time = int(parsed_time.group(1))
+ timestamp = datetime.datetime.fromtimestamp(parsed_time)
+ # returns the YYYY-MM-DD date format.
+ return timestamp.strftime("%Y-%b-%d")
return dict(env=env, prettydate=prettydate)
@@ -99,17 +110,26 @@ def err_abort(abort_status_code, **params):
def backend_post(endpoint, json):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.post(urljoin(BACKEND_URL, endpoint), json=json, headers=headers)
+ resp = requests.post(
+ urljoin(BACKEND_URL, endpoint), json=json, headers=headers
+ )
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)
+ err_abort(
+ 500,
+ message="Could not parse response from backend",
+ status_code=resp.status_code
+ )
if resp.status_code != 200:
- err_abort(500, message="Backend returned error status",
- json=response_json, status_code=resp.status_code)
+ err_abort(
+ 500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code
+ )
return response_json
@@ -123,7 +143,9 @@ def backend_post(endpoint, json):
def backend_get(endpoint, params):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.get(urljoin(BACKEND_URL, endpoint), params=params, headers=headers)
+ resp = requests.get(
+ urljoin(BACKEND_URL, endpoint), params=params, headers=headers
+ )
except requests.ConnectionError:
err_abort(500, message="Could not establish connection to backend")
try:
@@ -131,8 +153,12 @@ def backend_get(endpoint, params):
except ValueError:
err_abort(500, message="Could not parse response from backend")
if resp.status_code != 200:
- err_abort(500, message="Backend returned error status",
- json=response_json, status_code=resp.status_code)
+ err_abort(
+ 500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code
+ )
return response_json
@@ -144,9 +170,11 @@ def backend_get(endpoint, params):
# (and execution stack!).
@app.errorhandler(Exception)
def internal_error(e):
- return flask.render_template("templates/error.html",
- message="Internal error",
- stack=traceback.format_exc())
+ return flask.render_template(
+ "templates/error.html",
+ message="Internal error",
+ stack=traceback.format_exc()
+ )
##
@@ -156,8 +184,12 @@ def internal_error(e):
@app.route("/favicon.ico")
def favicon():
print("will look into: " + os.path.join(app.root_path, 'static'))
- return flask.send_from_directory(os.path.join(app.root_path, 'static'),
- "favicon.ico", mimetype="image/vnd.microsoft.ico")
+ return flask.send_from_directory(
+ os.path.join(app.root_path, 'static'),
+ "favicon.ico",
+ mimetype="image/vnd.microsoft.ico"
+ )
+
##
# Give information about the tip reserve status.
@@ -169,6 +201,13 @@ def survey_stats():
stats = backend_get("tip-query", dict(instance="default"))
return flask.render_template("templates/survey_stats.html", stats=stats)
+
+def get_qrcode_svg(data):
+ factory = qrcode.image.svg.SvgImage
+ img = qrcode.make(data, image_factory=factory)
+ return lxml.etree.tostring(img.get_image()).decode("utf-8")
+
+
##
# Tell the backend to 'authorize' a tip; this means that
# the backend will allocate a certain amount to be later
@@ -179,17 +218,29 @@ def survey_stats():
# otherwise.
@app.route("/submit-survey", methods=["POST"])
def submit_survey():
- tip_spec = dict(amount=CURRENCY + ":1.0",
- next_url=os.environ.get("TALER_ENV_URL_INTRO", "https://taler.net/"),
- instance="default",
- justification="Payment methods survey")
- resp = backend_post("tip-authorize", tip_spec)
-
- if resp.get("tip_redirect_url"):
- return flask.redirect(resp["tip_redirect_url"])
+ tip_spec = dict(
+ amount=CURRENCY + ":1.0",
+ next_url=os.environ.get("TALER_ENV_URL_INTRO", "https://taler.net/"),
+ instance="default",
+ justification="Payment methods survey"
+ )
+ backend_resp = backend_post("tip-authorize", tip_spec)
+
+ taler_tip_uri = backend_resp.get("taler_tip_uri")
+ if taler_tip_uri:
+ qrcode_svg = get_qrcode_svg(taler_tip_uri)
+ content = flask.render_template(
+ "templates/show_tip.html",
+ qrcode_svg=qrcode_svg,
+ taler_tip_uri=taler_tip_uri,
+ )
+ headers = {"Taler": taler_tip_uri}
+ return flask.Response(content, status=402, headers=headers)
+
+ err_abort(
+ 500, message="Tipping failed, unexpected backend response", json=resp
+ )
- err_abort(500, message="Tipping failed, unexpected backend response",
- json=resp)
##
# Serve the main index page.
@@ -197,4 +248,6 @@ def submit_survey():
# @return response object of the index page.
@app.route("/", methods=["GET"])
def index():
- return flask.render_template("templates/index.html", merchant_currency=CURRENCY)
+ return flask.render_template(
+ "templates/index.html", merchant_currency=CURRENCY
+ )
diff --git a/talersurvey/survey/templates/index.html b/talersurvey/survey/templates/index.html
index ffd8f61..e58e669 100644
--- a/talersurvey/survey/templates/index.html
+++ b/talersurvey/survey/templates/index.html
@@ -7,11 +7,7 @@
and get a nice tip - via your Taler wallet - from this shop! <a href={{ url_for('survey_stats') }}>(survey stats)</a>
</p>
</div>
- <div class="taler-installed-hide">
- <p>The survey is not possible without the wallet;
- please <a href="https://taler.net/wallet-installation.html">install one!</a></p>
- </div>
- <div class="taler-installed-show">
+ <div>
<form action="{{ url_for('submit_survey') }}" method="post" class="pure-form pure-form-stacked">
<legend>What do you prefer?</legend>
<fieldset>
diff --git a/talersurvey/survey/templates/show_tip.html b/talersurvey/survey/templates/show_tip.html
new file mode 100644
index 0000000..1c6317a
--- /dev/null
+++ b/talersurvey/survey/templates/show_tip.html
@@ -0,0 +1,35 @@
+{% extends "templates/base.html" %}
+
+
+{% block meta %}
+<noscript>
+ <meta http-equiv="refresh" content="1">
+</noscript>
+{% endblock meta %}
+
+{% block main %}
+
+<h1>Tip Offered</h1>
+
+<div class="taler-installed-hide">
+ <p>
+ Looks like your browser doesn't support GNU Taler payments. You can try
+ installing a <a href="https://taler.net/en/wallet.html">wallet browser extension</a>.
+ </p>
+</div>
+
+<div>
+
+ <p>
+ You can use this QR code to receive a tip with your mobile wallet:
+ </p>
+
+ {{ qrcode_svg | safe }}
+
+ <p>
+ Click <a href="{{ taler_tip_uri }}">this link</a> to open your system's Taler wallet if it exists.
+ </p>
+
+</div>
+
+{% endblock main %}
diff --git a/talersurvey/tests.py b/talersurvey/tests.py
index 512038e..360270c 100644
--- a/talersurvey/tests.py
+++ b/talersurvey/tests.py
@@ -35,5 +35,6 @@ class SurveyTestCase(unittest.TestCase):
survey.app.testing = True
self.app = survey.app.test_client()
+
if __name__ == "__main__":
unittest.main()