gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-merchant-frontends] branch stable updated (2d7427a -


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant-frontends] branch stable updated (2d7427a -> 8a211b3)
Date: Wed, 18 Oct 2017 10:01:22 +0200

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

marcello pushed a change to branch stable
in repository merchant-frontends.

    from 2d7427a  style alert message
     add b631289  /refund logic (mocked button)
     add a4880c1  fix crashes about /refund
     add e0ef4c1   #5090
     add c85e972  typo
     add 89ed99c  remove double if-else
     add 0f25b1c  error mgmt
     add f2d84c5  payed articles are kept in a dict, having article name as key 
and order_id as value
     add 46d89d1  add refund button + polishing
     add 9c0b4f6  Return 402 Payment Required for /refund increase
     add 1243fb4  Addressing #5068.
     add 6c79089  styling summary row
     add 85bec17  comment out backoffice link due to #4992
     add 2bfc844  fix #5069
     add 7174a23  fix /track methods + minor optimization to backoffice JS
     add 0813022  tinier history table
     add 9d25468  Separation between orders returned by tracking a transfer, 
and orders just gotten by scrolling.
     add 978119f  reducing font size for wtid marker
     add aa36fa7  nowrap for order ID column as well
     add 078d6e6  slight JS optimization
     add a345e0c  testcase infrastructure
     add fea52e9  involving the blog in tests
     add 534d4c8  testcase run README
     add 7b72f5a  test donations proposal creation ; URL arguments MUST be 
checked.
     add 3cc56f2  introducing failing test, as a reminder to implement 
arguments checking
     add 84800fd  fix unchecked /generate-contract arguments
     add 838b311  test bad donation receiver, use exceptions for 
'expect_parameter()'
     add 2ac0880  test /donate endpoint
     add 3888fd6  Finishing #5090.
     add 1ce4128  note
     add 92d6c46  don't show article after it was refunded
     add 1d51715  missing template file
     add afb80a1  fix markup
     add 742f956  check for refund on /pay
     add 8a211b3  fix tests run and authors.

No new revisions were added by this update.

Summary of changes:
 Makefile.in                                        |  7 ++
 README                                             | 17 +++++
 setup.py                                           |  4 +-
 talerfrontends/blog/blog.py                        | 88 ++++++++++++++++++----
 talerfrontends/blog/static/backoffice.css          | 16 ++++
 talerfrontends/blog/static/backoffice.js           | 73 +++++++++++-------
 talerfrontends/blog/templates/article_frame.html   |  4 +
 .../blog/templates/article_refunded.html           |  6 ++
 talerfrontends/blog/templates/backoffice.html      |  5 +-
 talerfrontends/donations/donations.py              | 26 +++++--
 talerfrontends/donations/templates/index.html      |  4 +-
 talerfrontends/helpers.py                          | 18 ++++-
 talerfrontends/tests.conf                          | 19 +++++
 talerfrontends/tests.py                            | 57 ++++++++++++++
 14 files changed, 289 insertions(+), 55 deletions(-)
 create mode 100644 talerfrontends/blog/templates/article_refunded.html
 create mode 100644 talerfrontends/tests.conf
 create mode 100755 talerfrontends/tests.py

diff --git a/Makefile.in b/Makefile.in
index d5c853b..33a902c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -48,3 +48,10 @@ install: $(templates) install-data
        @# force update when sources changed
        @pip3 install . --install-option="address@hidden@" --upgrade --no-deps
        cd talerfrontends/donations/static/web-common && make install && cd -
+
+# run testcases
+.PHONY: check
+check:
+       @export TALER_CONFIG_FILE=./talerfrontends/tests.conf; \
+        export address@hidden@/lib/python3.5/site-packages; \
+        python3 ./talerfrontends/tests.py
diff --git a/README b/README
index 6437ecb..5200145 100644
--- a/README
+++ b/README
@@ -94,3 +94,20 @@ the port they will listen to, can be either specified on the
 command line (option -p), or in the configuration file with the
 HTTP_PORT option. Note, launching the bank with 'serve-http',
 will make the UWSGI_SERVE option to be ignored.
+
+
+================== HOW TO TEST THE FRONTENDS =================
+
+First run ./configure script:
+
+$ . bootstrap
+$ ./configure
+
+In order to test the code withing your local working copy,
+use 'devinstall':
+
+$ make devinstall
+
+If everything worked fine, tests can be run in the following way:
+
+$ make check
diff --git a/setup.py b/setup.py
index e89f49f..9a74808 100755
--- a/setup.py
+++ b/setup.py
@@ -4,8 +4,8 @@ setup(name='talerfrontends',
       version='0.0',
       description='Example payment frontends for GNU Taler',
       url='git://taler.net/bank',
-      author='Florian Dold',
-      author_email='address@hidden',
+      author='Florian Dold, Marcello Stanisci',
+      author_email='address@hidden, address@hidden',
       license='GPL',
       packages=find_packages(),
       install_requires=["Flask>=0.10", "beautifulsoup4"],
diff --git a/talerfrontends/blog/blog.py b/talerfrontends/blog/blog.py
index 35fd073..02c6c2d 100644
--- a/talerfrontends/blog/blog.py
+++ b/talerfrontends/blog/blog.py
@@ -33,7 +33,8 @@ import datetime
 from pprint import pprint
 from talerfrontends.talerconfig import TalerConfig
 from talerfrontends.helpers import (make_url,
-expect_parameter, join_urlparts, get_query_string)
+        expect_parameter, join_urlparts, get_query_string,
+        backend_error)
 from talerfrontends.blog.content import (articles,
 get_article_file, get_image_file)
 
@@ -50,7 +51,7 @@ tc = TalerConfig.from_env()
 BACKEND_URL = tc["frontends"]["backend"].value_string(required=True)
 CURRENCY = tc["taler"]["currency"].value_string(required=True)
 INSTANCE = tc["blog"]["instance"].value_string(required=True)
-ARTICLE_AMOUNT = dict(value=0, fraction=10000000, currency=CURRENCY)
+ARTICLE_AMOUNT = dict(value=1, fraction=0, currency=CURRENCY)
 
 app.config.from_object(__name__)
 
@@ -75,17 +76,55 @@ def index():
 def javascript_licensing():
     return flask.render_template("templates/javascript.html")
 
+# Triggers the refund by serving /refund/test?order_id=XY.
+# Will be triggered by a "refund button".
address@hidden("/refund", methods=["GET", "POST"])
+def refund():
+    if flask.request.method == "POST":
+        payed_articles = flask.session["payed_articles"] = 
flask.session.get("payed_articles", {})
+        article_name = flask.request.form.get("article_name")
+        if not article_name:
+            return flask.jsonify(dict(error="No article_name found in form")), 
400
+        logger.info("Looking for %s to refund" % article_name)
+        order_id = payed_articles.get(article_name)
+        if not order_id:
+            return flask.jsonify(dict(error="Aborting refund: article not 
payed")), 401
+        r = requests.post(urljoin(BACKEND_URL, "refund"),
+                          json=dict(order_id=order_id,
+                                    refund=dict(value=1, fraction=0, 
currency=CURRENCY),
+                                    reason="Demo reimbursement",
+                                    instance=INSTANCE))
+        if 200 != r.status_code:
+            return backend_error(r)
+        payed_articles[article_name] = "__refunded"
+        response = flask.make_response()
+        response.headers["X-Taler-Refund-Url"] = make_url("/refund", 
("order_id", order_id))
+        return response, 402
+
+    else:
+        order_id = expect_parameter("order_id", False)
+        if not order_id:
+            logger.error("Missing parameter 'order_id'")
+            return flask.jsonify(dict(error="Missing parameter 'order_id'")), 
400
+        r = requests.get(urljoin(BACKEND_URL, "refund"), 
params=dict(order_id=order_id,
+                                                                     
instance=INSTANCE))
+        if 200 != r.status_code:
+            return backend_error(r)
+        return flask.jsonify(r.json()), r.status_code
+
 
 @app.route("/generate-contract", methods=["GET"])
 def generate_contract():
     article_name = expect_parameter("article_name")
+    pretty_name = article_name.replace("_", " ")
     order = dict(
+        summary=pretty_name,
         nonce=flask.request.args.get("nonce"),
         amount=ARTICLE_AMOUNT,
         max_fee=dict(value=1, fraction=0, currency=CURRENCY),
         products=[
             dict(
-                description="Essay: " + article_name.replace("_", " "),
+                description="Essay: " + pretty_name,
                 quantity=1,
                 product_id=0,
                 price=ARTICLE_AMOUNT,
@@ -101,12 +140,9 @@ def generate_contract():
         ),
         extra=dict(article_name=article_name),
     )
-    r = requests.post(urljoin(BACKEND_URL, 'proposal'), json=dict(order=order))
+    r = requests.post(urljoin(BACKEND_URL, "proposal"), json=dict(order=order))
     if r.status_code != 200:
-        try:
-            return flask.jsonify(r.json()), r.status_code
-        except json.decoder.JSONDecodeError:
-            return flask.jsonify(dict(error="Backend died, no JSON got from 
it")), 502
+        return backend_error(r)
     proposal_resp = r.json()
     return flask.jsonify(**proposal_resp)
 
@@ -121,7 +157,11 @@ def cc_payment(name):
 @app.route("/essay/<name>/data/<data>")
 def article(name, data=None):
     logger.info("processing %s" % name)
-    payed_articles = flask.session.get("payed_articles", [])
+    payed_articles = flask.session.get("payed_articles", {})
+
+    if payed_articles.get(name, "") == "__refunded":
+        return flask.render_template("templates/article_refunded.html", 
article_name=name)
+
     if name in payed_articles:
         article = articles[name]
         if article is None:
@@ -132,12 +172,16 @@ def article(name, data=None):
             else:
                 return "permission denied", 400
         return flask.render_template("templates/article_frame.html",
-                                     article_file=get_article_file(article))
+                                     article_file=get_article_file(article),
+                                     article_name=name)
 
     contract_url = make_url("/generate-contract", ("article_name",name))
     response = 
flask.make_response(flask.render_template("templates/fallback.html"), 402)
     response.headers["X-Taler-Contract-Url"] = contract_url
     response.headers["X-Taler-Contract-Query"] = "fulfillment_url"
+    # Useless (?) header, as X-Taler-Contract-Url takes always (?) precedence
+    # over X-Offer-Url.  This one might only be useful if the contract 
retrieval
+    # goes wrong.
     response.headers["X-Taler-Offer-Url"] = make_url("/essay/" + quote(name))
     return response
 
@@ -146,17 +190,25 @@ def article(name, data=None):
 def pay():
     deposit_permission = flask.request.get_json()
     if deposit_permission is None:
-        e = flask.jsonify(error="no json in body")
+        e = flask.jsonify(error="no json in body"),
         return e, 400
     r = requests.post(urljoin(BACKEND_URL, "pay"), json=deposit_permission)
     if 200 != r.status_code:
-        return flask.jsonify(r.json()), r.status_code
+        return backend_error(r)
     proposal_data = r.json()["contract_terms"]
     article_name = proposal_data["extra"]["article_name"]
-    payed_articles = flask.session["payed_articles"] = 
flask.session.get("payed_articles", [])
+    payed_articles = flask.session["payed_articles"] = 
flask.session.get("payed_articles", {})
+    if len(r.json()["refund_permissions"]) != 0:
+        # we had some refunds on the article purchase already!
+        logger.info("Article %s was refunded, before /pay" % article_name)
+        payed_articles[article_name] = "__refunded"
+        return flask.jsonify(r.json()), 200
+    if not deposit_permission["order_id"]:
+        logger.error("order_id missing from deposit_permission!")
+        return flask.jsonify(dict(error="internal error: ask for refund!")), 
500
     if article_name not in payed_articles:
-        payed_articles.append(article_name)
-
+        logger.info("Article %s goes in state" % article_name)
+        payed_articles[article_name] = deposit_permission["order_id"]
     return flask.jsonify(r.json()), 200
 
 
@@ -165,6 +217,8 @@ def history():
     qs = get_query_string().decode("utf-8")
     url = urljoin(BACKEND_URL, "history")
     r = requests.get(url, params=dict(parse_qsl(qs)))
+    if 200 != r.status_code:
+        return backend_error(r)
     return flask.jsonify(r.json()), r.status_code
 
 
@@ -179,6 +233,8 @@ def track_transfer():
     qs = get_query_string().decode("utf-8")
     url = urljoin(BACKEND_URL, "track/transfer")
     r = requests.get(url, params=dict(parse_qsl(qs)))
+    if 200 != r.status_code:
+        return backend_error(r)
     return flask.jsonify(r.json()), r.status_code
 
 
@@ -187,4 +243,6 @@ def track_order():
     qs = get_query_string().decode("utf-8")
     url = urljoin(BACKEND_URL, "track/transaction")
     r = requests.get(url, params=dict(parse_qsl(qs)))
+    if 200 != r.status_code:
+        return backend_error(r)
     return flask.jsonify(r.json()), r.status_code
diff --git a/talerfrontends/blog/static/backoffice.css 
b/talerfrontends/blog/static/backoffice.css
index 63a684c..1278d04 100644
--- a/talerfrontends/blog/static/backoffice.css
+++ b/talerfrontends/blog/static/backoffice.css
@@ -87,6 +87,17 @@ th {
   }
 }
 
+#marker {
+  text-align: center;
+  padding: 0px;
+  padding-bottom: 4px;
+  border: 0px;
+  border-bottom: 2px;
+  border-style: solid;
+  margin-bottom: 50px;
+  font-size: 70%;
+}
+
 .loader {
   margin-left: 30%;
   border: 7px solid #f3f3f3; /* Light grey */
@@ -105,4 +116,9 @@ th {
 .order-id, .wtid, .amount, .date {
   font-family: monospace;
   font-size: 140%;
+  white-space: nowrap;
+}
+
+.summary {
+  font-size: 90%;
 }
diff --git a/talerfrontends/blog/static/backoffice.js 
b/talerfrontends/blog/static/backoffice.js
index 4554bb0..6a77e93 100644
--- a/talerfrontends/blog/static/backoffice.js
+++ b/talerfrontends/blog/static/backoffice.js
@@ -84,9 +84,9 @@ function parse_date(date){
                 "Oct",
                 "Nov",
                 "Dec"];
-  var hours = ("0" + d.getUTCHours()).slice(-2);
-  var minutes = ("0" + d.getUTCMinutes()).slice(-2);
-  return `${d.getUTCDate()} ${months[d.getUTCMonth()]} ${d.getUTCFullYear()}, 
${hours}:${minutes}`;
+  var hours = ("0" + d.getHours()).slice(-2);
+  var minutes = ("0" + d.getMinutes()).slice(-2);
+  return `${d.getDate()} ${months[d.getMonth()]} ${d.getFullYear()}, 
${hours}:${minutes}`;
 }
 
 function toggle_overlay(force_close){
@@ -103,6 +103,18 @@ function toggle_overlay(force_close){
 
 }
 
+function make_marker(wtid){
+  var tr = document.createElement("tr");
+  var td = document.createElement("td");
+  var p = document.createElement("p");
+  td.setAttribute("colspan", 3);
+  p.textContent = wtid.substr(0, 20) + "...";
+  p.setAttribute("id", "marker");
+  td.appendChild(p);
+  tr.appendChild(td);
+  return tr;
+}
+
 function track_transfer(exchange, wtid){
   var loader = document.getElementsByClassName("loader")[0]; 
   loader.style.visibility = "visible";
@@ -111,7 +123,8 @@ function track_transfer(exchange, wtid){
   req.open("GET", qs, true);
   req.onload = function(){
     if(4 == req.readyState){
-      if(200 == req.status){
+      switch(req.status){
+      case 200:
         var tracks = JSON.parse(req.responseText);
         var table = document.getElementById("history");
         var tbody = xpath_get("tbody", table).snapshotItem(0);
@@ -119,16 +132,20 @@ function track_transfer(exchange, wtid){
         for(var i=0; i<tbody_children.snapshotLength; i++){
           tbody.removeChild(tbody_children.snapshotItem(i));
         }
-        fill_table(tracks.deposits_sums, tracks.execution_time);
         close_popup();
-      }
-      if(400 == req.status){
-        alert("Bad request, check submitted data!");
-        return; 
-      }
-      else{
+        fill_table(tracks.deposits_sums, tracks.execution_time);
+
+        // draw a line @ the bottom, mentioning the WTID.
+        var table = document.getElementById("history");
+        var tbody = xpath_get("tbody", table).snapshotItem(0);
+        var marker = make_marker(wtid);
+        tbody.appendChild(marker);
+        break;
+      case 400:
+        console.log("Bad request, check submitted data!");
+        break;
+      default:
         console.log(`Status: ${req.status}, not handled.`);
-        return;
       }
     }
   }
@@ -230,7 +247,8 @@ function fill_table(history, execution_time){
     var td_date = document.createElement("td");
     td_date.className = "date";
     td_order_id.innerHTML = `<a href="#${i}" 
onclick='track_order("${entry.order_id}", "FSF");'>${entry.order_id}</a>`;
-    td_summary.innerHTML = "TBD";
+    td_summary.className = "summary";
+    td_summary.innerHTML = entry.summary;
     td_amount.innerHTML = amount_to_string(entry.amount || 
entry.deposit_value);
     td_date.innerHTML = parse_date(entry.timestamp || execution_time);
     row.appendChild(td_order_id);
@@ -251,23 +269,24 @@ function fill_table(history, execution_time){
 }
 
 /**
- * Issue a direrct /track/order, via Web form.
+ * Issue a direrct /track via Web form.
  */
 function track_cherry_pick(form){
   var types = xpath_get("address@hidden'radio']", form);
-  var type = "order";
-  for(var i in [0, 1])
-    if (types.snapshotItem(i).checked)
-      type = types.snapshotItem(i).value;
-  if ("order" == type){
-    var order_id = xpath_get("address@hidden'order']", form).snapshotItem(0);
-    track_order(order_id.value, INSTANCE);
-  }
-  else{
-    var data = xpath_get("address@hidden'transfer']", form);
-    var wtid = data.snapshotItem(0);
-    var exchange = data.snapshotItem(1);
-    track_transfer(exchange.value, wtid.value);
+  for(var i in [0, 1]){
+    if (!types.snapshotItem(i).checked)
+      continue;
+    var type = types.snapshotItem(i).value;
+    if ("order" == type){
+      var order_id = xpath_get("address@hidden'order']", form).snapshotItem(0);
+      track_order(order_id.value, INSTANCE);
+    }
+    else{
+      var data = xpath_get("address@hidden'transfer']", form);
+      var wtid = data.snapshotItem(0);
+      var exchange = data.snapshotItem(1);
+      track_transfer(exchange.value, wtid.value);
+    }  
   }
 }
 
diff --git a/talerfrontends/blog/templates/article_frame.html 
b/talerfrontends/blog/templates/article_frame.html
index a2193d7..50d58e2 100644
--- a/talerfrontends/blog/templates/article_frame.html
+++ b/talerfrontends/blog/templates/article_frame.html
@@ -1,4 +1,8 @@
 {% extends "templates/base.html" %}
 {% block main %}
 {% include "articles/" + article_file %}
+  <form action="/refund" method="POST">
+    <input type="text" name="article_name" value={{ article_name}} hidden>
+    <input type="submit" value="Ask refund!">
+  </form>
 {% endblock main %}
diff --git a/talerfrontends/blog/templates/article_refunded.html 
b/talerfrontends/blog/templates/article_refunded.html
new file mode 100644
index 0000000..d6e49d7
--- /dev/null
+++ b/talerfrontends/blog/templates/article_refunded.html
@@ -0,0 +1,6 @@
+{% extends "templates/base.html" %}
+{% block main %}
+  <h1>Article refunded</h1>
+  Unfortunately you can't view the article {{ article_name }}, since the
+  payment for it was refunded.
+{% endblock main %}
diff --git a/talerfrontends/blog/templates/backoffice.html 
b/talerfrontends/blog/templates/backoffice.html
index 447ae54..b87495b 100644
--- a/talerfrontends/blog/templates/backoffice.html
+++ b/talerfrontends/blog/templates/backoffice.html
@@ -32,7 +32,10 @@
     </form>
   </div>
   <div id="history-container">
-    <table id="history" width="60%" style="visibility: hidden;">
+    <table id="history" width="50%" style="visibility: hidden;">
+      <col width="40">
+      <col width="40">
+      <col width="40">
       <tbody>
         <tr class="no-records">
           <th colspan="3">No records found</th>
diff --git a/talerfrontends/donations/donations.py 
b/talerfrontends/donations/donations.py
index 3bd8255..ffa34c8 100644
--- a/talerfrontends/donations/donations.py
+++ b/talerfrontends/donations/donations.py
@@ -28,7 +28,8 @@ import jinja2
 from talerfrontends.talerconfig import TalerConfig
 from talerfrontends.helpers import (make_url,
 expect_parameter, amount_from_float, amount_to_float,
-join_urlparts, get_query_string)
+join_urlparts, get_query_string, MissingParameterException,
+backend_error)
 
 logger = logging.getLogger(__name__)
 
@@ -46,8 +47,6 @@ MAX_FEE = dict(value=3, fraction=0, currency=CURRENCY)
 
 app.config.from_object(__name__)
 
-print(app.config)
-
 @app.context_processor
 def utility_processor():
     def url(my_url):
@@ -87,14 +86,18 @@ def checkout():
 
 @app.route("/generate-contract", methods=["GET"])
 def generate_contract():
-    donation_receiver = expect_parameter("donation_receiver")
-    donation_amount = expect_parameter("donation_amount")
+    try:
+        donation_receiver = expect_parameter("donation_receiver")
+        donation_amount = expect_parameter("donation_amount")
+    except MissingParameterException as e:
+        return flask.jsonify(dict(error="Missing parameter '%s'" % e)), 400
     amount = amount_from_float(float(donation_amount))
     order_id = "donation-%s-%X-%s" % \
                (donation_receiver,
                random.randint(0, 0xFFFFFFFF),
                datetime.today().strftime('%H_%M_%S'))
     order = dict(
+        summary="Donation!",
         nonce=flask.request.args.get("nonce"),
         amount=amount,
         max_fee=dict(value=1, fraction=0, currency=CURRENCY),
@@ -116,8 +119,13 @@ def generate_contract():
             jurisdiction="none",
         ),
     )
-    print("order: ", order)
     r = requests.post(urljoin(BACKEND_URL, 'proposal'), json=dict(order=order))
+    if 200 != r.status_code:
+        # It is important to use 'backend_error()', as it handles
+        # the case where the backend gives NO JSON as response.
+        # For example, if it dies, or nginx hijacks somehow the
+        # response.
+        return backend_error(r)
     return flask.jsonify(r.json()), r.status_code
 
 @app.route("/donate")
@@ -167,7 +175,7 @@ def pay():
         return e, 400
     r = requests.post(urljoin(BACKEND_URL, "pay"), json=deposit_permission)
     if 200 != r.status_code:
-        return flask.jsonify(r.json()), r.status_code
+        return backend_error(r)
     proposal_data = r.json()["contract_terms"]
     order_id = proposal_data["order_id"]
     payed_order_ids = flask.session["payed_order_ids"] = 
flask.session.get("payed_order_ids", {})
@@ -189,6 +197,8 @@ def history():
     qs = get_query_string().decode("utf-8")
     url = urljoin(BACKEND_URL, "history")
     r = requests.get(url, params=dict(parse_qsl(qs)))
+    if 200 != r.status_code:
+        return backend_error(r)
     return flask.jsonify(r.json()), r.status_code
 
 
@@ -198,4 +208,6 @@ def track_order():
     order_id = expect_parameter("order_id")
     url = urljoin(BACKEND_URL, "track/transaction")
     r = requests.get(url, params=dict(order_id=order_id, instance=instance))
+    if 200 != r.status_code:
+        return backend_error(r)
     return flask.jsonify(r.json()), r.status_code
diff --git a/talerfrontends/donations/templates/index.html 
b/talerfrontends/donations/templates/index.html
index 240e88b..0dc72a4 100644
--- a/talerfrontends/donations/templates/index.html
+++ b/talerfrontends/donations/templates/index.html
@@ -55,8 +55,8 @@ You are paying with an imaginary currency ({{ 
merchant_currency }}).
 </div>
 
 <h2>Back-office interface</h2>
-<p>Try the <a href="backoffice">back-office</a>, in order to track
+<!--p>Try the <a href="backoffice">back-office</a>, in order to track
 orders and corresponding deposits.
-</p>
+</p Depends on #4992 -->
 
 {% endblock %}
diff --git a/talerfrontends/helpers.py b/talerfrontends/helpers.py
index d406bb1..c19890d 100644
--- a/talerfrontends/helpers.py
+++ b/talerfrontends/helpers.py
@@ -16,6 +16,7 @@
 #  @author Marcello Stanisci
 
 from flask import request, jsonify, make_response, current_app, render_template
+import flask
 from urllib.parse import urljoin, urlencode
 import logging
 import requests
@@ -36,6 +37,10 @@ FRACTION_BASE = 1e8
 if not NDIGITS:
     NDIGITS = 2
 
+class MissingParameterException(Exception):
+    def __init__(self, param):
+        self.param = param
+
 def amount_to_float(amount):
     return amount['value'] + (float(amount['fraction']) / float(FRACTION_BASE))
 
@@ -80,9 +85,20 @@ def make_url(page, *query_params):
 def expect_parameter(name, alt=None):
     value = request.args.get(name, None)
     if value is None and alt is None:
-        return flask.jsonify(error="Missing parameter '%s'." % name), 400
+        logger.error("Missing parameter '%s'." % name)
+        raise MissingParameterException(name)
     return value if value else alt
 
 
 def get_query_string():
     return request.query_string
+
+def backend_error(requests_response):
+    logger.error("Backend error: status code: "
+                 + str(requests_response.status_code))
+    try:
+        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
diff --git a/talerfrontends/tests.conf b/talerfrontends/tests.conf
new file mode 100644
index 0000000..30d455e
--- /dev/null
+++ b/talerfrontends/tests.conf
@@ -0,0 +1,19 @@
+[taler]
+currency = TESTKUDOS
+
+[frontends]
+BACKEND = http://backend.test.taler.net/
+FRACTION = 100000000
+
+[donations]
+UWSGI_UNIXPATH_MODE = 660
+UWSGI_SERVE = unix
+UWSGI_UNIXPATH = $HOME/sockets/donations.uwsgi
+UWSGI_UNIXMODE = 666
+
+[blog]
+UWSGI_UNIXPATH_MODE = 660
+instance = FSF
+UWSGI_SERVE = unix
+UWSGI_UNIXPATH = $HOME/sockets/blog.uwsgi
+UWSGI_UNIXMODE = 666
diff --git a/talerfrontends/tests.py b/talerfrontends/tests.py
new file mode 100755
index 0000000..5068694
--- /dev/null
+++ b/talerfrontends/tests.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+
+"""
+Testing module, very limited: it is NOT able to mock
+a wallet (resume Python wallet?)!
+"""
+
+import unittest
+from donations import donations
+from blog import blog
+import logging
+
+logger = logging.getLogger(__name__)
+dapp = donations.app
+bapp = donations.app
+
+class DonationsTestCase(unittest.TestCase):
+    def setUp(self):
+        dapp.testing = True
+        self.app = dapp.test_client()
+
+    def test_root(self):
+        response = self.app.get("/") 
+        assert 200 == response.status_code
+
+    def test_proposal_creation(self):
+        qs = "/generate-contract?donation_receiver=Tor&donation_amount=1.0"
+        bad_qs = "/generate-contract?buggy=qs"
+        bad_receiver = 
"/generate-contract?donation_receiver=Torrone&donation_amount=2"
+        response = self.app.get(qs)
+        assert 200 == response.status_code
+        logger.info("Testing against bad query string")
+        response = self.app.get(bad_qs)
+        assert 400 == response.status_code
+        logger.info("Testing against bad donation receiver")
+        response = self.app.get(bad_receiver)
+        assert 404 == response.status_code
+
+    def test_donate(self):
+        qs = 
"/donate?donation_receiver=Tor&donation_amount=1&payment_system=taler"
+        response = self.app.get(qs)
+        print(response.status_code)
+        assert 402 == response.status_code
+
+class BlogTestCase(unittest.TestCase):
+    def setUp(self):
+        bapp.testing = True
+        self.app = bapp.test_client()
+
+    def test_root(self):
+        response = self.app.get("/") 
+        assert 200 == response.status_code
+
+
+
+if "__main__" == __name__:
+    unittest.main()

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



reply via email to

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