example.py (3509B)
1 import flask 2 import requests 3 from urllib.parse import urljoin, urlencode 4 import taler.util.amount 5 import base64 6 import os 7 import logging 8 import json 9 from random import randint 10 from datetime import datetime 11 12 13 app = flask.Flask(__name__) 14 app.secret_key = base64.b64encode(os.urandom(64)).decode('utf-8') 15 logger = logging.getLogger(__name__) 16 17 CURRENCY = "TESTKUDOS" 18 BACKEND_URL = "http://backend.test.taler.net/" 19 20 def make_url(page, *query_params): 21 """ 22 Return a URL to a page in the current Flask application with the given 23 query parameters (sequence of key/value pairs). 24 """ 25 query = urlencode(query_params) 26 if page.startswith("/"): 27 root = flask.request.url_root 28 page = page.lstrip("/") 29 else: 30 root = flask.request.base_url 31 url = urljoin(root, "%s?%s" % (page, query)) 32 # urlencode is overly eager with quoting, the wallet right now 33 # needs some characters unquoted. 34 return url.replace("%24", "$").replace("%7B", "{").replace("%7D", "}") 35 36 @app.route("/") 37 def index(): 38 return flask.render_template("index.html") 39 40 41 @app.route("/donate") 42 def donate(): 43 response = flask.Response(status=402) 44 response.headers["X-Taler-Contract-Url"] = "/generate-proposal" 45 return response 46 47 48 @app.route("/generate-proposal") 49 def generate_proposal(): 50 DONATION = amount.string_to_amount("0.1:%s" % CURRENCY) 51 MAX_FEE = amount.string_to_amount("0.05:%s" % CURRENCY) 52 ORDER_ID = "tutorial-%X-%s" % (randint(0, 0xFFFFFFFF), datetime.today().strftime("%H_%M_%S")) 53 order = dict( 54 order_id=ORDER_ID, 55 nonce=flask.request.args.get("nonce"), 56 amount=DONATION, 57 max_fee=MAX_FEE, 58 products=[ 59 dict( 60 description="Donation", 61 quantity=1, 62 product_id=0, 63 price=DONATION, 64 ), 65 ], 66 fulfillment_url=make_url("/fulfillment", ("order_id", ORDER_ID)), 67 pay_url=make_url("/pay"), 68 merchant=dict( 69 instance="tutorial", 70 address="nowhere", 71 name="Donation tutorial", 72 jurisdiction="none", 73 ), 74 ) 75 76 url = urljoin(BACKEND_URL, "proposal") 77 78 r = requests.post(url, json=dict(order=order)) 79 if r.status_code != 200: 80 logger.error("failed to POST to '%s'", url) 81 return r.text, r.status_code 82 proposal_resp = r.json() 83 return flask.jsonify(**proposal_resp) 84 85 86 @app.route("/fulfillment") 87 def fulfillment(): 88 paid = flask.session.get("paid", False) 89 if paid: 90 return "Thank you! Your order id is: <b>%s</b>." % flask.session["order_id"] 91 92 response = flask.Response(status=402) 93 response.headers["X-Taler-Contract-Url"] = make_url("/generate-contract") 94 response.headers["X-Taler-Contract-Query"] = "fulfillment_url" 95 response.headers["X-Taler-Offer-Url"] = make_url("/donate") 96 97 return response 98 99 100 @app.route("/pay", methods=["POST"]) 101 def pay(): 102 deposit_permission = flask.request.get_json() 103 if deposit_permission is None: 104 e = flask.jsonify(error="no json in body") 105 return e, 400 106 r = requests.post(urljoin(BACKEND_URL, 'pay'), json=deposit_permission) 107 if 200 != r.status_code: 108 logger.error("Backend said, status code: %d, object: %s" % (r.status_code, r.text)) 109 return r.text, r.status_code 110 contract_terms = r.json()["contract_terms"] 111 flask.session["paid"] = True 112 flask.session["order_id"] = contract_terms["order_id"] 113 return flask.jsonify(r.json()), 200