merchant-frontend-examples

ZZZ: Inactive/Deprecated
Log | Files | Refs

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