gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-api] branch master updated: remove outdated merchant


From: gnunet
Subject: [GNUnet-SVN] [taler-api] branch master updated: remove outdated merchant store example, obsoleted by tutorial
Date: Fri, 03 Mar 2017 17:02:21 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository api.

The following commit(s) were added to refs/heads/master by this push:
     new 7bf82f8  remove outdated merchant store example, obsoleted by tutorial
7bf82f8 is described below

commit 7bf82f8dffebe39b0a557a58d0dd030f080658f7
Author: Florian Dold <address@hidden>
AuthorDate: Fri Mar 3 17:02:20 2017 +0100

    remove outdated merchant store example, obsoleted by tutorial
---
 docs/example-essay-store.rst | 625 -------------------------------------------
 1 file changed, 625 deletions(-)

diff --git a/docs/example-essay-store.rst b/docs/example-essay-store.rst
deleted file mode 100644
index c76ce51..0000000
--- a/docs/example-essay-store.rst
+++ /dev/null
@@ -1,625 +0,0 @@
-..
-  This file is part of GNU TALER.
-
-  Copyright (C) 2014, 2015, 2016 INRIA
-
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU General Public License as published by the Free Software
-  Foundation; either version 2.1, or (at your option) any later version.
-
-  TALER 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
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-
-  @author Marcello Stanisci
-
-====================
-Example: Essay Store
-====================
-
-This section shows how to set up a merchant :ref:`frontend <merchant-arch>`, 
and is
-inspired by our demonstration shop running at `https://shop.demo.taler.net/`.
-It is recommended that the reader is already familiar with the
-:ref:`payment protocol and terminology <payprot>`.
-
-The code we are going to describe is available at
-https://git.taler.net/merchant-frontends.git/tree/talerfrontends/blog
-and is implemented in Python+Flask.
-
-The desired effect is the homepage showing a list of buyable articles, and 
once the
-user clicks one of them, they will either get the Taler
-`contract <https://api.taler.net/api-merchnat.html#contract>`_
-or a credit card paywall if they have no Taler wallet installed.
-
-Each article thus links to a `offer URL`, whose layout is shown below.
-
-  `https://shop.demo.taler.net/essay/Appendix_A:_A_Note_on_Software`
-
-Once the server side logic receives a request for a offer URL, it needs to
-instruct the wallet to retrieve a Taler contract.  This action can be taken
-either with or **without** the use of JavaScript, see the next section.
-
------------------------
-Triggering the contract
------------------------
-
-It is important to note that the contract is not returned simply
-as the offer URL's response, but rather the frontend `instructs`
-the browser on how to retrieve the contract.  That is needed for
-the right handling of the cases where the wallet is not installed.
-
-.. note::
-
-  The code samples shown below are intentionally "incomplete", as often
-  one function contains logic for multiple actions.  Thus in order to not
-  mix concepts form different actions under one section, parts of code not
-  related to the section being documented have been left out.
-
-**With JavaScript**
-
-In this case, the objective is to call the function 
``taler.offerContractFrom()`` into the user browser, which will then retrieve 
the
-contract.  In order to do that, we return a HTML page, whose
-template is in ``talerfrontends/blog/templates/purchase.html``,
-that imports ``taler-wallet-lib.js``, so that the function
-``taler.offerContractFrom()`` can be invoked into the user's
-browser.
-
-The server side handler for a offer URL needs to render ``purchase.html`` by 
passing
-the right parameters to ``taler.offerContractFrom()``.
-
-The rendering is done by the ``article`` function at 
``talerfrontends/blog/blog.py``,
-and is done by Flask's ``render_template()``, see below.
-
-.. sourcecode:: python
-
-  # 'name' is the article name, and is set to the right value
-  # by Flask
-  # The 'data' parameter is used to send images along
-  # the articles, however its use is beyond the scope of
-  # this survey.
-  def article(name, data=None):
-      ...
-      ...
-
-      return render_template('templates/purchase.html',
-                              article_name=name,
-                              no_contract=1,
-                              contract_url=quote(contract_url),
-                              data_attribute="data-taler-contractoffer=%s" % 
contract_url)
-
-After the rendering, (part of) ``purchase.html`` will look like shown below.
-
-.. sourcecode:: html
-
-  <html>
-    <head>
-      <!-- ... -->
-      <script src="/static/web-common/taler-wallet-lib.js" 
type="application/javascript"></script>
-      <script src="/static/purchase.js" type="application/javascript"></script>
-      <!-- ... -->
-      <meta name="contract_url" 
value="https://shop.demo.taler.net/generate-contract?article_name=Appendix_A:_A_Note_on_Software";>
-
-    </head>
-    <body>
-      <!-- ... -->
-      <!-- ... -->
-  
-      <div id="ccfakeform" class="fade">
-        <p>
-        Oops, it looks like you don't have a Taler wallet installed.  Why 
don't you enter
-        all your credit card details before reading the article? <em>You can 
also
-        use GNU Taler to complete the purchase at any time.</em>
-        </p>
-        <form>
-          First name<br> <input type="text"></input><br>
-          Family name<br> <input type="text"></input><br>
-          Age<br> <input type="text"></input><br>
-          Nationality<br> <input type="text"></input><br>
-          Gender<br> <input type="radio" name="gender">Male</input>
-          CC number<br> <input type="text"></input><br>
-          <input type="radio" name="gender">Female</input><br>
-        </form>
-
-        <form method="get" action="/cc-payment/{{ article_name }}">
-          <input type="submit"></input>
-        </form>
-      </div>
-    
-      <div id="talerwait">
-        <em>Processing payment with GNU Taler, please wait <span 
id="action-indicator"></span></em>
-      </div>
-      <!-- ... -->
-    </body>
-  </html>
-
-
-The script ``purchase.js`` is now in charge of implementing the behaviour we 
seek.
-It needs to register two handlers: one called whenever the wallet is detected 
in the
-browser, the other if the user has no wallet installed.
-
-That is done with:
-
-.. sourcecode:: javascript
-
-  taler.onPresent(handleWalletPresent);
-  taler.onAbsent(handleWalletAbsent);
-
-Note that the ``taler`` object is exported by ``taler-wallet-lib.js``, and 
contains all
-is needed to communicate with the wallet.
-
-
-``handleWalletAbsent`` doesn't need to do much: it has to only hide the 
"please wait"
-message and uncover the credit card pay form.  See below.
-
-.. sourcecode:: javascript
-
-  function handleWalletAbsent() {
-    // Hide "please wait" message
-    document.getElementById("talerwait").style.display = "none";
-    // Uncover credit card pay form
-    document.body.style.display = "";
-  }
-
-On the other hand, ``handleWalletPresent`` needs to firstly hide the credit 
card
-pay form and show the "please wait" message.  After that, it needs to fetch the
-contract URL from the responsible ``meta`` tag, and finally invoke 
``taler.offerContractFrom()`` using it.  See below both parts.
-
-.. sourcecode:: javascript
-
-  function handleWalletPresent() {
-    // Hide credit card paywall
-    document.getElementById("ccfakeform").style.display = "none";
-    // Show "please wait" message
-    document.getElementById("talerwait").style.display = "";
-    ...
-    ...
-      // Fetch contract URL from 'meta' tag.
-      let contract_url = document.querySelectorAll("[name=contract_url]")[0];
-      // If this call is successful, it will obtain the contract,
-      // hand it to the wallet, so the wallet can eventually
-      // show it to the user.
-      
taler.offerContractFrom(decodeURIComponent(contract_url.getAttribute("value")));
-    ...
-  }
-
-.. note::
-
-  In order to get our code validated by W3C validators, we can't have inline
-  JavaScript in our pages, we are forced to import any used script instead.
-
-**Without JavaScript**
-
-This case is handled by the function ``article`` defined in
-``talerfrontends/blog/blog.py``.  Its objective is to set the "402 Payment
-Required" HTTP status code, and the HTTP header ``X-Taler-Contract-Url``
-to the actual contract's URL for this purchase.
-
-Upon returning such a response, the wallet will automatically fetch the
-contract from the URL indicated by ``X-Taler-Contract-Url``, and show it
-to the user.
-
-Below is shown how the function ``article`` prepares and returns such a
-response.
-
-.. sourcecode:: python
-
-  # 'name' is the article name, and is set to the right value
-  # by Flask
-  # The 'data' parameter is used to send images along
-  # the articles, however its use is beyond the scope of
-  # this survey.
-  def article(name, data=None):
-      ...
-      ...
-
-      # Create response.
-      response = make_response(render_template('templates/fallback.html'), 402)
-      # Set "X-Taler-Contract-Url" header to the contract's URL.
-      response.headers["X-Taler-Contract-Url"] = contract_url
-      return response
-
-The ``make_response`` function is exported by Flask, so it's beyond the scope
-of this document to explain it;  however, it returns a "response object" having
-the "402 Payment Required" as HTTP status code, and the
-HTML file ``talerfrontends/blog/templates/fallback.html`` as the body.
-``fallback.html`` contains the credit card pay form, so that if the wallet is
-not installed, the browser would keep that page shown.
-
-``contract_url`` is defined in the earlier steps of the same function; however,
-in this example it looks like:
-
-  
`https://shop.demo.taler.net/essay/generate-contract?article_name=Appendix_A:_A_Note_on_Software`.
-
-The frontend will also have to provide the contract.  That is done
-by the handler ``generate_contract``, defined in
-``talerfrontends/blog/blog.py``.  See below.
-
-.. sourcecode:: python
-
-  def generate_contract():
-      now = int(time.time())
-      tid = random.randint(1, 2**50)
-      article_name = expect_parameter("article_name")
-      contract = make_contract(article_name=article_name, tid=tid, 
timestamp=now)
-      contract_resp = sign_contract(contract)
-      logger.info("generated contract: %s" % str(contract_resp))
-      return jsonify(**contract_resp)
-
-
-Its task is to feed the ``make_contract`` subroutine with all the
-values it needs to generate a contract.  Those values are: the timestamp
-for the contract, the transaction ID, and the article name; respectively,
-``now``, ``tid``, and ``article_name``.
-
-After ``make_contract`` returns, the variable ``contract`` will hold a
-`dict` type that complies with a contract
-`proposition <https://api.taler.net/api-merchnat.html#proposition>`_
-We then call ``sign_contract`` feeding it with the proposition, so that
-it can forward it to the backend and return it signed.  Finally we return
-the signed proposition, complying with the
-`Offer <https://api.taler.net/api-merchant.html#contract>`_ object.
-
-For simplicity, any article costs the same price, so the frontend
-doesn't need to map articles to prices.
-
-Both ``make_contract`` and ``sign_contract`` are defined in
-``talerfrontends/blog/helpers.py``.
-
-At this point, the user can accept the contract, which triggers the wallet
-to visit the fulfillment page.  The main logic for a fulfillment page handler
-is to (1) return the claimed product, if it has been paid, or (2) instruct the
-wallet to send the payment.
-
------------------
-Fulfillment logic
------------------
-
-The state accounts for a product being paid or not, so the fulfillment handler
-will firstly check that:
-
-.. sourcecode:: python
-
-  # 'name' is the article name, and is set to the right value
-  # by Flask
-  # The 'data' parameter is used to send images along
-  # the articles, however its use is beyond the scope of
-  # this survey.
-  def article(name, data=None):
-      # Get list of payed articles from the state
-      payed_articles = session.get("payed_articles", [])
-
-      if name in payed_articles:
-          ...
-          # The articles has been paid, so return it to the
-          # customer.
-          return send_file(get_article_file(article))
-      ...
-
-In case the article has not been paid yet, the fulfillment handler needs
-to `reconstruct` the contract, in order to get a precise reference about the
-purchase in being served.
-
-All the information needed to reconstruct the contract is contained in the
-fulfillment URL parameters.  See below the URL layout:
-
-  
`https://shop.demo.taler.net/essay/Appendix_A:_A_Note_on_Software?uuid=<CONTRACT-HASHCODE>&timestamp=<TIMESTAMP>tid=<TRANSACTION_ID>`
-
-The way the contract is reconstructed is exactly the same as it was generated
-in the previous steps:  we need to call ``make_contract`` to get the original
-`proposition <https://api.taler.net/api-merchnat.html#proposition>`_ and then
-``sign_contract``.  Recall that aside from allowing the backend to add missing
-fields to the proposition, ``sign_contract`` returns the contract hashcode 
also,
-that we should compare with the ``uuid`` parameter provided by the wallet.
-
-In our blog, all the fulfillment logic is implemented in the function 
``article``,
-defined in ``talerfrontends/blog/blog.py``.  It is important to note that this
-function is `the same` function that runs the offer URL; in fact, as long as 
your
-URL design allows it, it is not mandatory to split up things.  In our example, 
the
-offer URL differs from the fulfillment URL respect to the number (and type) of
-parameters, so the ``article`` function can easily decide whether it has to 
handle
-a "offer" or a "fulfillment" case.  See below how the function detects the 
right
-case and reconstructs the contract.
-
-.. sourcecode:: python
-
-  # 'name' is the article name, and is set to the right value
-  # by Flask
-  # The 'data' parameter is used to send images along
-  # the articles, however its use is beyond the scope of
-  # this survey.
-  def article(name, data=None):
-
-      ...
-      hc = request.args.get("uuid")
-      tid_str = request.args.get("tid")
-      timestamp_str = request.args.get("timestamp")
-      if hc is None or tid_str is None or timestamp_str is None:
-          # Offer URL case.
-          contract_url = make_url("/generate-contract", ("article_name",name))
-          ... # Go on operating the offer URL and return
-    
-      # Fulfillment URL case from here on.
-      try:
-          tid = int(tid_str)
-      except ValueError:
-          raise MalformedParameterError("tid")
-      try:
-          timestamp = int(timestamp_str)
-      except ValueError:
-          raise MalformedParameterError("timestamp")
-
-  restored_contract = make_contract(article_name=name, tid=tid, 
timestamp=timestamp)
-  contract_resp = sign_contract(restored_contract)
-
-  # Return error if uuid mismatch with the hashcode coming from the backend
-  if contract_resp["h_proposal_data"] != hc:
-      e = jsonify(error="contract mismatch", was=hc, 
expected=contract_resp["h_proposal_data"])
-      return e, 400
-
-   # We save the article's name in the state since after
-   # receiving the payment this value will point to the
-   # article to be delivered to the customer.  Note how the
-   # contract's hashcode is used to index the state.
-   session[hc] = si = session.get(hc, {})
-   si['article_name'] = name
-
-
-After a successful contract reconstruction, the handler needs to instruct
-the wallet to actually send the payment.  There are as usual two ways this
-can be accomplished: with and without JavaScript.
-
-**With JavaScript**
-
-..
-  Mention that the template is the same we used for a offer URL!
-
-We return a HTML page, whose template is in
-``talerfrontends/blog/templates/purchase.html``, that imports 
``taler-wallet-lib.js``,
-so that the function ``taler.executePayment()`` can be invoked into the user's
-browser.
-
-The fulfillment handler needs to render ``purchase.html`` so that the right
-parameters get passed to ``taler.executePayment()``.
-
-See below how the function ``article`` does the rendering.
-
-.. sourcecode:: python
-
-  # 'name' is the article name, and is set to the right value
-  # by Flask
-  # The 'data' parameter is used to send images along
-  # the articles, however its use is beyond the scope of
-  # this survey.
-  def article(name, data=None):
-
-      ...
-      ...
-    
-      return render_template('templates/purchase.html',
-                             hc=hc,
-                             pay_url=quote(pay_url),
-                             offering_url=quote(offering_url),
-                             article_name=name,
-                             no_contract=0,
-                             
data_attribute="data-taler-executecontract=%s,%s,%s" % (hc, pay_url, 
offering_url))
-
-After the rendering, (part of) ``purchase.html`` will look like shown below.
-
-.. sourcecode:: html
-
-  ...
-  <script src="/static/web-common/taler-wallet-lib.js" 
type="application/javascript"></script>
-  <script src="/static/purchase.js" type="application/javascript"></script>
-  ...
-  <meta name="pay_url" value="https://shop.demo.taler.net/pay";>
-  <meta name="offering_url" 
value="https://shop.demo.taler.net/essay/Appendix_A:_A_Note_on_Software";>
-  <!-- Fake hashcode -->
-  <meta name="hc" value="D7D5HDJRP36GTBBRGHXP7204VR773HHQBNFFCY5YY4P18026PAJ0">
-
-  ...
-  ...
-
-  <div id="ccfakeform" class="fade">
-    <p>
-    Oops, it looks like you don't have a Taler wallet installed.  Why don't 
you enter
-    all your credit card details before reading the article? <em>You can also
-    use GNU Taler to complete the purchase at any time.</em>
-    </p>
-  
-    <form>
-      <!-- Credit card pay form. -->
-    </form>
-  </div>
-  
-  <div id="talerwait">
-    <em>Processing payment with GNU Taler, please wait <span 
id="action-indicator"></span></em>
-  </div>
-  ...
-
-The script ``purchase.js`` is now in charge of calling 
``taler.executePayment()``.
-It will try to register two handlers: one called whenever the wallet is 
detected in the
-browser, the other if the user has no wallet installed.
-
-That is done with:
-
-.. sourcecode:: javascript
-
-  taler.onPresent(handleWalletPresent);
-  taler.onAbsent(handleWalletAbsent);
-
-.. note::
-  
-  So far, the template and the imported script (``purchase.js``)
-  are exactly the same as the offer URL case, since we use them
-  for both cases.  See below how the script distinguishes "offer"
-  from "fulfillment" case.
-
-Note that the ``taler`` object is exported by ``taler-wallet-lib.js``, and 
contains all
-is needed to communicate with the wallet.
-
-
-``handleWalletAbsent`` doesn't need to do much: it has to only hide the 
"please wait"
-message and uncover the credit card pay form.  See below.
-
-.. sourcecode:: javascript
-
-  function handleWalletAbsent() {
-    // Hide "please wait" message
-    document.getElementById("talerwait").style.display = "none";
-    // Uncover credit card pay form
-    document.body.style.display = "";
-  }
-
-On the other hand, ``handleWalletPresent`` needs to firstly hide the credit 
card
-pay form and show the "please wait" message.  After that, it needs to fetch the
-needed parameters from the responsible ``meta`` tags, and finally invoke
-``taler.offerContractFrom()`` using those parameters.  See below its whole 
definition.
-Note, that since we are in the fulfillment case, the credit card pay form is 
`almost`
-useless, as it is highly unlikely that the wallet is not installed.
-
-.. sourcecode:: javascript
-
-  function handleWalletPresent() {
-    // Hide the credit card pay form
-    document.getElementById("ccfakeform").style.display = "none";
-    // Show "please wait" message
-    document.getElementById("talerwait").style.display = "";
-
-    // The `no_contract` value is provided by the function `article` via a
-    // 'meta' tag in the template.  When this value equals 1, then we are in 
the
-    // "offer" URL case, otherwise we are in the "fulfillment" URL case.
-    let no_contract = document.querySelectorAll("[name=no_contract]")[0];
-    if (Number(no_contract.getAttribute("value"))) {
-      // "Offer" case
-      let contract_url = document.querySelectorAll("[name=contract_url]")[0];
-      
taler.offerContractFrom(decodeURIComponent(contract_url.getAttribute("value")));
-    }
-    else {
-      // "Fulfillment" case.
-      let hc = document.querySelectorAll("[name=hc]")[0];
-      let pay_url = document.querySelectorAll("[name=pay_url]")[0];
-      let offering_url = document.querySelectorAll("[name=offering_url]")[0];
-      taler.executePayment(hc.getAttribute("value"),
-                           decodeURIComponent(pay_url.getAttribute("value")),
-                           
decodeURIComponent(offering_url.getAttribute("value")));
-    }
-  }
-
-Once the browser executes ``taler.executePayment(...)``, the wallet will send 
the coins
-to ``pay_url``.  Once the payment succeeds, the wallet will again visit the
-fulfillment URL, this time getting the article thanks to the "payed" status 
set by
-the ``pay_url`` handler.
-
-**Without JavaScript**
-
-This case is handled by the function ``article`` defined in
-``talerfrontends/blog/blog.py``.  Its objective is to set the "402 Payment
-Required" HTTP status code, along with the HTTP headers 
``X-Taler-Contract-Hash``,
-``X-Taler-Pay-Url``, and ``X-Taler-Offer-Url``.
-
-..
-  FIXME:
-  Are those three parameters previously introduced?
-
-Upon returning such a response, the wallet will automatically send the
-payment to the URL indicated in ``X-Taler-Pay-Url``.
-
-The excerpt below shows how the function ``article`` prepares and returns such 
a
-response.
-
-.. sourcecode:: python
-
-  # 'name' is the article name, and is set to the right value
-  # by Flask
-  # The 'data' parameter is used to send images along
-  # the articles, however its use is beyond the scope of
-  # this survey.
-  def article(name, data=None):
-  ...
-
-      # 'make_response' is exported by Flask.  It returns a
-      # "response object" with customizable status code, HTTP
-      # headers and body
-      response = make_response(render_template('templates/fallback.html'), 402)
-      response.headers["X-Taler-Contract-Hash"] = hc
-      response.headers["X-Taler-Pay-Url"] = pay_url
-      response.headers["X-Taler-Offer-Url"] = offering_url
-      return response
-
-The template ``fallback.html`` contains the credit card pay form, which will be
-used in the rare case where the wallet would not be detected in a fulfillment
-session.  Once the payment succeeds, the wallet will again visits the
-fulfillment URL, this time getting the article thanks to the "payed" status 
set by
-the ``pay_url`` handler.
-
----------
-Pay logic
----------
-
-The pay handler for the blog is implemented by the function
-``pay`` at ``talerfrontends/blog/blog.py``.  Its main duty is to receive the
-`deposit permission 
<https://api.taler.net/api-merchant.html#DepositPermission>`_
-from the wallet, forward it to the backend, and return the outcome
-to the wallet.  See below the main steps of its implementation.
-
-.. sourcecode:: python
-
-  def pay():
-      # Get the uploaded deposit permission
-      deposit_permission = request.get_json()
-
-      if deposit_permission is None:
-          e = jsonify(error="no json in body")
-          return e, 400
-
-      # Pick the contract's hashcode from deposit permission
-      hc = deposit_permission.get("h_proposal_data")
-
-      # Return error if no hashcode was found
-      if hc is None:
-          e = jsonify(error="malformed deposit permission", 
hint="h_proposal_data missing")
-          return e, 400
-
-      # Get a handle to the state for this contract, using the
-      # hashcode from deposit permission as the index
-      si = session.get(hc)
-
-      # If no session was found for this contract, then either it
-      # expired or one of the hashcodes (the one we got from 
-      # reconstructing the contract in the fulfillment handler,
-      # and the one we just picked from the deposit permission)
-      # is bogus.  Note how using the contract's hashcode as index
-      # makes harder for the wallet to use different hashcodes
-      # in different steps of the protocol.
-      if si is None:
-          e = jsonify(error="no session for contract")
-          return e, 400 
-
-      # Forward the deposit permission to the backend
-      r = requests.post(urljoin(BACKEND_URL, 'pay'), json=deposit_permission)
-
-      # Return error if the backend returned a HTTP status code
-      # other than 200 OK
-      if 200 != r.status_code:
-          raise BackendError(r.status_code, r.text)
-
-      # The payment went through..
-      ...
-
-      # Resume the article name
-      article = si["article_name"]
-
-      # Set the article's state as "payed".  This is realized by
-      # appending it to a *list* of articles the customer is currently
-      # allowed to read.
-      payed_articles = session["payed_articles"] = 
session.get("payed_articles", [])
-      if article not in payed_articles:
-          payed_articles.append(article)
-
-      ...
-
-      # Return success
-      return r.text, 200

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]