summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcello Stanisci <marcello.stanisci@inria.fr>2016-01-20 18:15:46 +0100
committerMarcello Stanisci <marcello.stanisci@inria.fr>2016-01-20 18:15:46 +0100
commit44b4a0b20e798756826d7e3175e453b439e758dc (patch)
tree50e13f2b902f572979ec002fbd821d99fa01d2e2
parent09b3cfee78cebd84cfec64ce28cd5d39be0a12d2 (diff)
downloadmerchant-44b4a0b20e798756826d7e3175e453b439e758dc.tar.gz
merchant-44b4a0b20e798756826d7e3175e453b439e758dc.tar.bz2
merchant-44b4a0b20e798756826d7e3175e453b439e758dc.zip
Adding most of blog-type website.
-rw-r--r--src/frontend/checkout.php2
-rw-r--r--src/frontend_blog/README20
-rw-r--r--src/frontend_blog/articles/essay-x.html19
-rw-r--r--src/frontend_blog/blog_lib.php26
-rw-r--r--src/frontend_blog/essay_checkout.php244
-rw-r--r--src/frontend_blog/essay_contract.php78
-rw-r--r--src/frontend_blog/essay_fulfillment.php20
-rw-r--r--src/frontend_blog/essay_pay.php75
-rw-r--r--src/frontend_blog/execute.js33
-rw-r--r--src/frontend_blog/execute.php56
-rw-r--r--src/frontend_blog/execute.tsx41
-rw-r--r--src/frontend_blog/index.html79
-rw-r--r--src/frontend_blog/style.css123
-rw-r--r--src/frontend_blog/teaser.php46
-rw-r--r--src/frontend_lib/merchants.php91
15 files changed, 952 insertions, 1 deletions
diff --git a/src/frontend/checkout.php b/src/frontend/checkout.php
index 21d4d8c4..cf789b11 100644
--- a/src/frontend/checkout.php
+++ b/src/frontend/checkout.php
@@ -237,7 +237,7 @@ function taler_wallet_unload_cb(aEvent)
(as the extension may be loaded/enabled after the page was loaded) */
function signal_taler_wallet_onload()
{
- var eve = new Event('taler-checkout-probe');
+ var eve = new Event('taler-probe');
document.dispatchEvent(eve);
};
diff --git a/src/frontend_blog/README b/src/frontend_blog/README
new file mode 100644
index 00000000..8cfb490f
--- /dev/null
+++ b/src/frontend_blog/README
@@ -0,0 +1,20 @@
+This directory contains the files implementing the frontend of the new merchant architecture.
+
+Only tested on nginx. To run the website, it suffices to have all the .php and .html files
+in the same directory, and having PHP (with the extension 'pecl_http' enabled) enabled.
+
+File |What implements
+--------------------------------
+o index.html | The homepage. Here it is possible to decide how much donate
+ to whom you would like.
+
+o fake_wire_transfer.php | PHP script that takes the wire transfer request and passes it on
+ | to the /admin/add/incoming API of the demo-mint.
+
+o checkout.php | The "payment selection" that is the form
+ that allows the user to choose the payment method he wishes to use.
+ It also implements the request of certificate and trigger the certificate
+ viewer in the extension when it arrives in the customer's machine.
+
+o pay.php | Actual receiving of money, plus it gives back a "fullfillment" page
+ that informs the user of his well ended deal.
diff --git a/src/frontend_blog/articles/essay-x.html b/src/frontend_blog/articles/essay-x.html
new file mode 100644
index 00000000..48db9115
--- /dev/null
+++ b/src/frontend_blog/articles/essay-x.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <title>Blog site demonstration</title>
+ <link rel="stylesheet" type="text/css" href="style.css">
+</head>
+<body>
+ <div id="teaser">
+ <p>
+ The x essay is
+ </p>
+ </div>
+ <div id="full-article">
+ <p>
+ about something
+ </p>
+ </div>
+</body>
+</html>
diff --git a/src/frontend_blog/blog_lib.php b/src/frontend_blog/blog_lib.php
new file mode 100644
index 00000000..4238e993
--- /dev/null
+++ b/src/frontend_blog/blog_lib.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * Take a (article's) filename and return its
+ * teaser. It has the articles folder hardcoded
+ */
+function get_teaser($name){
+ $content = file_get_contents("articles/$name.html");
+ $doc = new DOMDocument();
+ $doc->loadHTML($content);
+ $teaser = $doc->getElementById("teaser");
+ return $teaser;
+}
+
+/**
+ * Take a (article's) filename and return its
+ * DOM. It has the articles folder hardcoded
+ */
+function get_article($name){
+ $content = file_get_contents("articles/$name.html");
+ $doc = new DOMDocument();
+ $doc->loadHTML($content);
+ return $doc;
+}
+
+?>
diff --git a/src/frontend_blog/essay_checkout.php b/src/frontend_blog/essay_checkout.php
new file mode 100644
index 00000000..c013d7c5
--- /dev/null
+++ b/src/frontend_blog/essay_checkout.php
@@ -0,0 +1,244 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Blog - Payment method - Taler Demo</title>
+ <link rel="stylesheet" type="text/css" href="style.css">
+ <script>
+ /*
+ @licstart The following is the entire license notice for the
+ JavaScript code in this page.
+
+ Copyright (C) 2014,2015 GNUnet e.V.
+
+ The JavaScript code in this page is free software: you can
+ redistribute it and/or modify it under the terms of the GNU
+ Lesser General Public License (GNU LGPL) as published by the
+ Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version. The code is distributed WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU LGPL for more details.
+
+ As additional permission under GNU LGPL version 3 section 7, you
+ may distribute non-source (e.g., minimized or compacted) forms of
+ that code without the copy of the GNU LGPL normally required by
+ section 4, provided you include this license notice and a URL
+ through which recipients can access the Corresponding Source.
+
+ @licend The above is the entire license notice
+ for the JavaScript code in this page.
+ */
+ </script>
+</head>
+<body onload="signal_taler_wallet_onload()">
+
+ <header>
+ <div id="logo">
+ <svg height="100" width="100">
+ <circle cx="50" cy="50" r="40" stroke="darkcyan" stroke-width="6" fill="white" />
+ <text x="19" y="82" font-family="Verdana" font-size="90" fill="darkcyan">S</text>
+ </svg>
+ </div>
+
+ <h1>Blog - Select payment method</h1>
+ </header>
+
+ <aside class="sidebar" id="left">
+ </aside>
+
+ <section id="main">
+ <article>
+
+ <h1>Select your payment method</h1>
+
+ <p>
+ This is an example for a "checkout" page of a Web shop.
+ On the previous page, you have created the shopping cart
+ and decided which product to buy (i.e. which project to
+ donate KUDOS to). Now in this page, you are asked to
+ select a payment option. As Taler is not yet universally
+ used, we expect merchants will offer various payment options.
+ </p>
+ <p>
+ The page also demonstrates how to only enable (or show) the Taler
+ option if Taler is actually supported by the browser. For example,
+ if you disable the Taler extension now, the Taler payment option
+ will be disabled in the page. Naturally, you could also trivially
+ hide the Taler option entirely by changing the visibility instead.
+ </p>
+ <p>
+ Note that you MUST select Taler here for the demo to continue,
+ as the other payment options are just placeholders and not
+ really working in the demonstration. Also, it is of course
+ possible to ask the user to make this choice already on the
+ previous page (with the shopping cart), we just separated the
+ two steps to keep each step as simple as possible.
+ </p>
+
+ <form name="tform" action="" method="POST">
+ <div id="opt-form" align="left"><br>
+ <input type="radio" name="payment_system" value="lisa"
+ id="lisa-radio-button-id">Lisa</input>
+ <br/>
+ <input type="radio" name="payment_system" value="ycard">You Card</input>
+ <br/>
+ <input type="radio" name="payment_system" value="cardme">Card Me</input>
+ <br/>
+ <input type="radio" name="payment_system" value="taler"
+ id="taler-radio-button-id" disabled="true">Taler</input>
+ <br/>
+ <input type="button" onclick="pay(this.form)" value="Ok"></input>
+ </div>
+ </form>
+
+ </article>
+ </section>
+
+<script type="text/javascript">
+
+/* This function is called from "taler_pay" after
+ we downloaded the JSON contract from the merchant.
+ We now need to pass it to the extension. */
+function handle_contract(json_contract)
+{
+ var cEvent = new CustomEvent('taler-contract', { detail: json_contract });
+
+ document.dispatchEvent(cEvent);
+};
+
+
+/* Trigger Taler contract generation on the server, and pass the
+ contract to the extension once we got it. */
+function taler_pay(form)
+{
+ var contract_request = new XMLHttpRequest();
+
+ /* Note that the URL we give here is specific to the Demo-shop
+ and not required by the protocol: each web shop can
+ have its own way of generating and transmitting the
+ contract, there just must be a way to get the contract
+ and to pass it to the wallet when the user selects 'Pay'. */
+ contract_request.open("GET", "essay_contract.php", true);
+ contract_request.onload = function (e)
+ {
+ if (contract_request.readyState == 4)
+ {
+ if (contract_request.status == 200)
+ {
+ /* display contract_requestificate (i.e. it sends the JSON string
+ to the extension) alert (contract_request.responseText); */
+ console.log("response text:", contract_request.responseText);
+ handle_contract(contract_request.responseText);
+ }
+ else
+ {
+ /* There was an error obtaining the contract from the merchant,
+ obviously this should not happen. To keep it simple, we just
+ alert the user to the error. */
+ alert("Failure to download contract from merchant " +
+ "(" + contract_request.status + "):\n" +
+ contract_request.responseText);
+ }
+ }
+ };
+ contract_request.onerror = function (e)
+ {
+ /* There was an error obtaining the contract from the merchant,
+ obviously this should not happen. To keep it simple, we just
+ alert the user to the error. */
+ alert("Failure requesting the contract:\n" + contract_request.statusText);
+ };
+ contract_request.send(null);
+}
+
+
+/* This function is called when the user presses the
+ 'Ok' button. We are now supposed to trigger the
+ "corret" payment system logic. For this demo, we
+ only handle "taler". */
+function pay(form)
+{
+ for (var cnt=0; cnt < form.payment_system.length; cnt++)
+ {
+ var choice = form.payment_system[cnt];
+ if (choice.checked)
+ {
+ if (choice.value == "taler")
+ {
+ taler_pay(form);
+ }
+ else
+ {
+ alert(choice.value + ": NOT available in this demo!");
+ }
+ }
+ }
+};
+
+
+/* The following event gets fired whenever a customer has a Taler
+ wallet installed in his browser. In that case, the webmaster can decide
+ whether or not to display/enable Taler as a payment option in the dialog. */
+function has_taler_wallet_cb(aEvent)
+{
+ // enable the Taler payment option from the form
+ var tbutton = document.getElementById("taler-radio-button-id");
+ tbutton.removeAttribute("disabled");
+ tbutton.setAttribute("checked", "true");
+};
+
+
+/* Function called when the Taler extension was unloaded;
+ here we disable the Taler option and check "Lisa", as
+ some "valid" option should always be selected. */
+function taler_wallet_unload_cb(aEvent)
+{
+ var tbutton = document.getElementById("taler-radio-button-id");
+ tbutton.setAttribute("disabled", "true");
+ var lbutton = document.getElementById("lisa-radio-button-id");
+ lbutton.setAttribute("checked", "true");
+};
+
+
+/* The merchant signals its taler-friendlyness to the wallet,
+ thereby causing the wallet to make itself more visible in the menu.
+ This function should be called both when the page is loaded
+ (i.e. via body's onload) and when we receive a "taler-load" signal
+ (as the extension may be loaded/enabled after the page was loaded) */
+function signal_taler_wallet_onload()
+{
+ var eve = new Event('taler-probe');
+ document.dispatchEvent(eve);
+};
+
+
+// function included to be run to test the page despite a
+// wallet not being present in the browser. Enables the
+// Taler option. NOT needed in real deployments.
+function test_without_wallet(){
+ var tbutton = document.getElementById("taler-radio-button-id");
+ tbutton.removeAttribute("disabled");
+};
+
+
+// /////////////// Main logic run first ////////////////////////
+
+// Register event to be triggered by the wallet as a response to our
+// first event
+document.addEventListener("taler-wallet-present",
+ has_taler_wallet_cb,
+ false);
+
+// Register event to be triggered by the wallet when it gets enabled while
+// the user is on the payment page
+document.addEventListener("taler-load",
+ signal_taler_wallet_onload,
+ false);
+
+// Register event to be triggered by the wallet when it is unloaded
+document.addEventListener("taler-unload",
+ taler_wallet_unload_cb,
+ false);
+</script>
+</body>
+</html>
diff --git a/src/frontend_blog/essay_contract.php b/src/frontend_blog/essay_contract.php
new file mode 100644
index 00000000..4aeb8c99
--- /dev/null
+++ b/src/frontend_blog/essay_contract.php
@@ -0,0 +1,78 @@
+<?php
+/*
+ This file is part of GNU TALER.
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser 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, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * This file should:
+ *
+ * 1. check if some article is going to be bought
+ * 2. check if the wallet is installed TODO
+ * 3. get the contract (having the teaser as product detail) to the wallet
+ *
+ */
+include("../frontend_lib/merchants.php");
+include("./blog_lib.php");
+session_start();
+if (!isset($_SESSION['article'])){
+ echo "Please land here just to buy articles";
+ die();
+ }
+$article = $_SESSION['article'];
+// 2 to-do
+
+// send contract
+$transaction_id = rand(0, 1001);
+$p_id = hexdec(substr(sha1($article), -5));
+$teatax = array ('value' => 1,
+ 'fraction' => 0,
+ 'currency' => "KUDOS");
+$now = new DateTime('now');
+$teaser = get_teaser($article);
+$pay_url = "essay_pay.php";
+$exec_url = "execute.php";
+$contract_json = generate_contract(1,
+ 0,
+ "KUDOS",
+ $transaction_id,
+ trim($teaser->nodeValue),
+ $p_id,
+ $teatax,
+ $now,
+ $pay_url,
+ $exec_url);
+$resp = give_to_backend($_SERVER["HTTP_HOST"],
+ "backend/contract",
+ $contract_json);
+
+// Our response code is the same we got from the backend:
+$status_code = $resp->getResponseCode();
+http_response_code ($status_code);
+
+// Now generate our body
+if ($status_code != 200)
+{
+ echo "Error while generating the contract";
+ echo $resp->body->toString ();
+}
+else
+{ $got_json = json_decode ($resp->body->toString ());
+ $_SESSION['H_contract'] = $got_json->H_contract;
+ $_SESSION['article_value'] = 1;
+ $_SESSION['article_fraction'] = 0;
+ $_SESSION['article_currency'] = "KUDOS";
+ echo $resp->body->toString ();
+}
+?>
diff --git a/src/frontend_blog/essay_fulfillment.php b/src/frontend_blog/essay_fulfillment.php
new file mode 100644
index 00000000..df2f8cfa
--- /dev/null
+++ b/src/frontend_blog/essay_fulfillment.php
@@ -0,0 +1,20 @@
+<?php
+
+session_start();
+
+if (!isset($_GET['article'])){
+ http_response_code(400);
+ echo "No article specified";
+ die();
+}
+$article = $_GET['article'];
+/* check if the client is allowed to get the wanted article */
+if(!isset($_SESSION['allowed_articles'][$article])){
+ http_response_code(401); // unauthorized
+ echo "Not allowed to read this article";
+ die();
+}
+// get the article
+$article_doc = get_article($article);
+echo $article_doc->saveHTML();
+?>
diff --git a/src/frontend_blog/essay_pay.php b/src/frontend_blog/essay_pay.php
new file mode 100644
index 00000000..6d906b74
--- /dev/null
+++ b/src/frontend_blog/essay_pay.php
@@ -0,0 +1,75 @@
+<?php
+/*
+ This file is part of GNU TALER.
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser 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, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * This file should:
+ * 1. Check if the session is valid
+ * 2. augment the deposit permission with missin values
+ * 3. forward payment to backend
+ */
+
+if (!isset($_SESSION['H_contract']))
+{
+ echo "No session active.";
+ http_response_code (301);
+ return;
+}
+
+$article = $_SESSION['article'];
+$post_body = file_get_contents('php://input');
+$deposit_permission = json_decode ($post_body, true);
+$to_add = array('max_fee' => array('value' => 3,
+ 'fraction' => 8,
+ 'currency' => $_SESSION['currency']),
+ 'amount' => array('value' => $_SESSION['article_value'],
+ 'fraction' => $_SESSION['article_fraction'],
+ 'currency' => $_SESSION['article_currency']));
+$complete_deposit_permission = array_merge($deposit_permission, $to_add);
+$resp = give_to_backend($_SERVER['HTTP_HOST'],
+ "backend/pay",
+ $complete_deposit_permission);
+$status_code = $resp->getResponseCode();
+// Our response code is the same we got from the backend:
+http_response_code ($status_code);
+
+// Now generate our body
+if ($status_code != 200)
+{
+ /* error: just forwarding to the wallet what
+ gotten from the backend (which is forwarding 'as is'
+ the error gotten from the mint) */
+ echo json_encode ($new_deposit_permission);
+ echo "Error came from the backend, payment undone. Status $status_code\n";
+ echo "\n";
+ echo $resp->body->toString ();
+}
+else
+{
+ $_SESSION['payment_ok'] = true;
+ if (!isset($_SESSION['allowed_articles'])){
+ $_SESSION['allowed_articles'] = array ($_SESSION['article'] => true);
+ else $_SESSION['allowed_articles'] =
+ array_push($_SESSION['allowed_articles'], array ($article => true));
+ }
+
+ http_response_code (301);
+ $url = (new http\URL($_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']))
+ ->mod(array ("path" => "essay_fulfillment.php?article=$article"), http\Url::JOIN_PATH);
+ header("Location: $url");
+ die();
+}
+
diff --git a/src/frontend_blog/execute.js b/src/frontend_blog/execute.js
new file mode 100644
index 00000000..a9045cb5
--- /dev/null
+++ b/src/frontend_blog/execute.js
@@ -0,0 +1,33 @@
+"use strict";
+// JSX literals are compiled to calls to React.createElement calls.
+let React = {
+ createElement: function (tag, props, ...children) {
+ let e = document.createElement(tag);
+ for (let k in props) {
+ e.setAttribute(k, props[k]);
+ }
+ for (let child of children) {
+ if ("string" === typeof child || "number" == typeof child) {
+ child = document.createTextNode(child);
+ }
+ e.appendChild(child);
+ }
+ return e;
+ }
+};
+document.addEventListener("DOMContentLoaded", function (e) {
+ var eve = new CustomEvent('taler-execute-payment', { detail: { H_contract: h_contract } });
+ document.dispatchEvent(eve);
+});
+function replace(el, r) {
+ el.parentNode.replaceChild(r, el);
+}
+document.addEventListener("taler-payment-result", function (e) {
+ if (!e.detail.success) {
+ alert("Payment failed\n" + JSON.stringify(e.detail));
+ return;
+ }
+ console.log("finished payment");
+ let msg = React.createElement("div", null, "Payment successful. View your ", React.createElement("a", {"href": e.detail.fulfillmentUrl}, "product"), ".");
+ replace(document.getElementById("loading"), msg);
+});
diff --git a/src/frontend_blog/execute.php b/src/frontend_blog/execute.php
new file mode 100644
index 00000000..33021fd3
--- /dev/null
+++ b/src/frontend_blog/execute.php
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <title>Toy Store - Taler Demo</title>
+ <link rel="stylesheet" type="text/css" href="style.css">
+ <script> /* @licstart The following is the entire license notice for the
+ JavaScript code in this page.
+
+ Copyright (C) 2015 GNUnet e.V.
+
+ The JavaScript code in this page is free software: you can
+ redistribute it and/or modify it under the terms of the GNU
+ Lesser General Public License (GNU LGPL) as published by the Free Software
+ Foundation, either version 2.1 of the License, or (at your option)
+ any later version. The code is distributed WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU LGPL for more details.
+
+ As additional permission under GNU LGPL version 2.1 section 7, you
+ may distribute non-source (e.g., minimized or compacted) forms of
+ that code without the copy of the GNU LGPL normally required by
+ section 4, provided you include this license notice and a URL
+ through which recipients can access the Corresponding Source.
+
+ @licend The above is the entire license notice
+ for the JavaScript code in this page.
+ */
+ </script>
+ <script type="text/javascript">
+<?php
+session_start();
+echo "var h_contract=\"$_SESSION[H_contract]\";\n";
+?>
+ </script>
+ <script type="text/javascript" src="execute.js"></script>
+</head>
+
+<body>
+ <header>
+ <div id="logo">
+ <svg height="100" width="100">
+ <circle cx="50" cy="50" r="40" stroke="darkcyan" stroke-width="6" fill="white" />
+ <text x="19" y="82" font-family="Verdana" font-size="90" fill="darkcyan">S</text>
+ </svg>
+ </div>
+ <h1>Toy Store - Taler Demo</h1>
+ </header>
+
+ <aside class="sidebar" id="left">
+ </aside>
+
+ <section id="main">
+ <h1>Executing Payment ...</h1>
+ <div id="loading">Loading...</div>
+</body>
+</html>
diff --git a/src/frontend_blog/execute.tsx b/src/frontend_blog/execute.tsx
new file mode 100644
index 00000000..67cf8e06
--- /dev/null
+++ b/src/frontend_blog/execute.tsx
@@ -0,0 +1,41 @@
+"use strict";
+
+
+// JSX literals are compiled to calls to React.createElement calls.
+let React = {
+ createElement: function(tag, props, ...children) {
+ let e = document.createElement(tag);
+ for (let k in props) {
+ e.setAttribute(k, props[k]);
+ }
+ for (let child of children) {
+ if ("string" === typeof child || "number" == typeof child) {
+ child = document.createTextNode(child);
+ }
+ e.appendChild(child);
+ }
+ return e;
+ }
+};
+
+declare var h_contract: string;
+
+document.addEventListener("DOMContentLoaded", function (e) {
+ var eve = new CustomEvent('taler-execute-payment', {detail: {H_contract: h_contract}});
+ document.dispatchEvent(eve);
+});
+
+function replace(el, r) {
+ el.parentNode.replaceChild(r, el);
+}
+
+document.addEventListener("taler-payment-result", function (e: CustomEvent) {
+ if (!e.detail.success) {
+ alert("Payment failed\n" + JSON.stringify(e.detail));
+ return;
+ }
+ console.log("finished payment");
+ let msg =
+ <div>Payment successful. View your <a href={e.detail.fulfillmentUrl}>product</a>.</div>;
+ replace(document.getElementById("loading"), msg);
+});
diff --git a/src/frontend_blog/index.html b/src/frontend_blog/index.html
new file mode 100644
index 00000000..a1ad1db7
--- /dev/null
+++ b/src/frontend_blog/index.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <title>Blog site demonstration</title>
+ <link rel="stylesheet" type="text/css" href="style.css">
+ <script type="text/javascript">
+ /* @licstart The following is the entire license notice for the
+ JavaScript code in this page.
+
+ Copyright (C) 2015 GNUnet e.V.
+
+ The JavaScript code in this page is free software: you can
+ redistribute it and/or modify it under the terms of the GNU
+ Lesser General Public License (GNU LGPL) as published by the Free Software
+ Foundation, either version 2.1 of the License, or (at your option)
+ any later version. The code is distributed WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU LGPL for more details.
+
+ As additional permission under GNU LGPL version 2.1 section 7, you
+ may distribute non-source (e.g., minimized or compacted) forms of
+ that code without the copy of the GNU LGPL normally required by
+ section 4, provided you include this license notice and a URL
+ through which recipients can access the Corresponding Source.
+
+ @licend The above is the entire license notice
+ for the JavaScript code in this page.
+ */
+ </script>
+</head>
+
+<body>
+ <header>
+ <div id="logo">
+ <svg height="100" width="100">
+ <circle cx="50" cy="50" r="40" stroke="darkcyan" stroke-width="6" fill="white" />
+ <text x="19" y="82" font-family="Verdana" font-size="90" fill="darkcyan">B</text>
+ </svg>
+ </div>
+
+ <h1>Blog site demonstration</h1>
+ </header>
+
+ <aside class="sidebar" id="left">
+ </aside>
+
+ <section id="main">
+ <article>
+ <h1>Welcome to the Taler blog</h1>
+ <p>This blog simulates how a website selling articles which integrates
+ Taler should work. If you don't have a Taler wallet installed,
+ please visit <a href="https://demo.taler.net">demo.taler.net</a>.
+ By clicking on some article below, you get its teaser shown, but the
+ actual purchase happens once you will click on the 'read more' link
+ associated with that teaser.
+ </p>
+ </article>
+ <section>
+
+ <article>
+ <h2>Articles list</h2>
+ </article>
+
+ <article class="articles">
+ <ul style="list-style-type:none">
+ <li>
+ <a href="/teaser.php?article=essay-x">
+ <div class="teasers_item">
+ <h3>Essay x</h3>
+ <p>In essay x, we will ...</p>
+ </div>
+ </a>
+ </li>
+ </ul>
+ </article>
+ </section>
+ </section>
+</body>
+</html>
diff --git a/src/frontend_blog/style.css b/src/frontend_blog/style.css
new file mode 100644
index 00000000..c2cc51ee
--- /dev/null
+++ b/src/frontend_blog/style.css
@@ -0,0 +1,123 @@
+body {
+ background-color: white;
+ margin: 0;
+ padding: 0;
+ font-family: Verdana, sans;
+}
+
+header {
+ width: 100%;
+ height: 100px;
+ margin: 0;
+ padding: 0;
+ border-bottom: 1px solid black;
+}
+
+header h1 {
+ font-size: 200%;
+ margin: 0;
+ padding: 0 0 0 120px;
+ position: relative;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+header #logo {
+ float: left;
+ width: 100px;
+ padding: 0;
+ margin: 0;
+ text-align: center;
+ border-right: 1px solid black;
+}
+
+aside {
+ width: 100px;
+ float: left;
+}
+
+section#main {
+ margin: 0 0 0 100px;
+ padding: 20px;
+ border-left: 1px solid black;
+ height: 100%;
+ max-width: 40em;
+}
+
+section#main h1:first-child {
+ margin-top: 0;
+}
+
+h1 {
+ font-size: 160%;
+}
+
+h2 {
+ font-size: 140%;
+}
+
+h3 {
+ font-size: 120%;
+}
+
+h4, h5, h6 {
+ font-size: 100%;
+}
+
+.loader {
+ font-size: 10px;
+ margin: 50px auto;
+ text-indent: -9999em;
+ width: 11em;
+ height: 11em;
+ border-radius: 50%;
+ background: #ffffff;
+ background: -moz-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%);
+ background: -webkit-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%);
+ background: -o-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%);
+ background: -ms-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%);
+ position: relative;
+ -webkit-animation: load3 1.4s infinite linear;
+ animation: load3 1.4s infinite linear;
+ -webkit-transform: translateZ(0);
+ -ms-transform: translateZ(0);
+ transform: translateZ(0);
+}
+
+.loader:after {
+ background: #fff;
+ width: 75%;
+ height: 75%;
+ border-radius: 50%;
+ content: '';
+ margin: auto;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+}
+
+@-webkit-keyframes load3 {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes load3 {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+
diff --git a/src/frontend_blog/teaser.php b/src/frontend_blog/teaser.php
new file mode 100644
index 00000000..e5f2e97b
--- /dev/null
+++ b/src/frontend_blog/teaser.php
@@ -0,0 +1,46 @@
+<html>
+<?php
+/*
+ This file is part of GNU TALER.
+ Copyright (C) 2014, 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser 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, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * This file should:
+ *
+ * 1. fetch the article teaser and attach a 'read more' link to it
+ *
+ */
+$article = (isset($_GET['article']) ? $_GET['article'] : "No article");
+$content = file_get_contents("articles/$article.html");
+$doc = new DOMDocument();
+$doc->loadHTML($content);
+$teaser = $doc->getElementById("teaser");
+?>
+<head>
+ <title>
+ <?php echo $article ?>
+ </title>
+</head>
+<body>
+<?php if ($article == "No article")
+ echo "Please select some article";
+ else {
+ session_start();
+ $_SESSION['article'] = $article;
+ echo $teaser->nodeValue
+ . "<br><a href=\"/essay_checkout.php\">read more</a>";}; ?>
+
+<body>
+</html>
diff --git a/src/frontend_lib/merchants.php b/src/frontend_lib/merchants.php
new file mode 100644
index 00000000..bbb0d90e
--- /dev/null
+++ b/src/frontend_lib/merchants.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Return a contract proposition to forward to the backend
+ * Note that `teatax` is an associative array representing a
+ * Taler-style amount (so it has the usual <amount,fration,currency>
+ * triple). Moreover, `teatax` should be a *list* of taxes
+ */
+function generate_contract($amount_value,
+ $amount_fraction,
+ $currency,
+ $transaction_id,
+ $desc,
+ $p_id,
+ $teatax,
+ $now,
+ $pay_url,
+ $exec_url){
+ $contract = array ('amount' => array ('value' => $amount_value,
+ 'fraction' => $amount_fraction,
+ 'currency' => $currency),
+ 'max_fee' => array ('value' => 3,
+ 'fraction' => 01010,
+ 'currency' => $currency),
+ 'transaction_id' => $transaction_id,
+ 'products' => array (
+ array ('description' => $desc,
+ 'quantity' => 1,
+ 'price' => array ('value' => $amount_value,
+ 'fraction' => $amount_fraction,
+ 'currency' => $currency),
+ 'product_id' => $p_id,
+ 'taxes' => array (array ('teatax' => $teatax)),
+ 'delivery_date' => "Some Date Format",
+ 'delivery_location' => 'LNAME1')),
+ 'timestamp' => "/Date(" . $now->getTimestamp() . ")/",
+ 'pay_url' => $pay_url,
+ 'exec_url' => $exec_url,
+ 'expiry' => "/Date(" . $now->add(new DateInterval('P2W'))->getTimestamp() . ")/",
+ 'refund_deadline' => "/Date(" . $now->add(new DateInterval('P3M'))->getTimestamp() . ")/",
+ 'merchant' => array ('address' => 'LNAME2',
+ 'name' => 'test merchant',
+ 'jurisdiction' => 'LNAME3'),
+
+ 'locations' => array ('LNAME1' => array ('country' => 'Test Country',
+ 'city' => 'Test City',
+ 'state' => 'Test State',
+ 'region' => 'Test Region',
+ 'province' => 'Test Province',
+ 'ZIP code' => 4908,
+ 'street' => 'test street',
+ 'street number' => 20),
+ 'LNAME2' => array ('country' => 'Test Country',
+ 'city' => 'Test City',
+ 'state' => 'Test State',
+ 'region' => 'Test Region',
+ 'province' => 'Test Province',
+ 'ZIP code' => 4908,
+ 'street' => 'test street',
+ 'street number' => 20),
+ 'LNAME3' => array ('country' => 'Test Country',
+ 'city' => 'Test City',
+ 'state' => 'Test State',
+ 'region' => 'Test Region',
+ 'province' => 'Test Province',
+ 'ZIP code' => 4908)));
+ $json = json_encode (array ('contract' => $contract, 'exec_url' => $exec_url, 'pay_url' => $pay_url), JSON_PRETTY_PRINT);
+ return $json;
+}
+
+
+
+/**
+ * Feed `$json` to the backend and return the "(pecl) http response object"
+ * corresponding to the `$backend_relative_url` call
+ */
+function give_to_backend($backend_host, $backend_relative_url, $json){
+ $url = (new http\URL("http://$backend_host"))
+ ->mod(array ("path" => $backend_relative_url), http\Url::JOIN_PATH);
+
+ $req = new http\Client\Request("POST",
+ $url,
+ array ("Content-Type" => "application/json"));
+
+ $req->getBody()->append($json);
+
+ // Execute the HTTP request
+ $client = new http\Client;
+ $client->enqueue($req)->send();
+ return $client->getResponse();
+}
+?>