gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated: Access API: implement create transacti


From: gnunet
Subject: [libeufin] branch master updated: Access API: implement create transactions.
Date: Wed, 01 Dec 2021 10:43:15 +0100

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

ms pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new 4482f8d4 Access API: implement create transactions.
4482f8d4 is described below

commit 4482f8d42bab26a787e154a3466be03d5d51d3b5
Author: ms <ms@taler.net>
AuthorDate: Wed Dec 1 10:42:41 2021 +0100

    Access API: implement create transactions.
---
 cli/bin/libeufin-cli                               | 43 +++++++++++++++++++-
 .../main/kotlin/tech/libeufin/sandbox/Helpers.kt   | 46 +++++++++++++++++-----
 .../src/main/kotlin/tech/libeufin/sandbox/JSON.kt  | 10 +++++
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  | 31 ++++++++++++++-
 4 files changed, 118 insertions(+), 12 deletions(-)

diff --git a/cli/bin/libeufin-cli b/cli/bin/libeufin-cli
index d264b5ac..f7333aaa 100755
--- a/cli/bin/libeufin-cli
+++ b/cli/bin/libeufin-cli
@@ -1187,11 +1187,52 @@ def sandbox_bankaccount(ctx):
 
 # This group deals with the new Access API
 # and the 'demobank' model.
-@sandbox.group("demobank", help="manage customers")
+@sandbox.group(
+    "demobank",
+    help="Subcommands for the 'demobank' model and the Access API."
+)
 @click.pass_context
 def sandbox_demobank(ctx):
     pass
 
+@sandbox_demobank.command("new-transaction", help="Initiate a new 
transaction.")
+@click.option(
+    "--bank-account",
+    help="Label of the bank account to be debited for the transaction.",
+    required=True
+)
+# Including the subject in the payto to match the
+# payto returned by the merchant backend helper program
+# to create tip reserves.
+@click.option(
+    "--payto-with-subject",
+    help="Payto address including the subject as a query parameter.",
+    required=True
+)
+@click.option(
+    "--amount",
+    help="Amount to transfer, in the $currency:X.Y format.",
+    required=True
+)
+@click.pass_obj
+def sandbox_demobank_new_transaction(obj, bank_account, payto_with_subject, 
amount):
+    # expected to include the demobank name.
+    sandbox_base_url = obj.require_sandbox_base_url()
+    url = urljoin_nodrop(sandbox_base_url, 
f"/access-api/accounts/{bank_account}/transactions")
+    try:
+        body = dict(paytoUri=payto_with_subject, amount=amount)
+        resp = post(
+            url,
+            json=body,
+            auth=auth.HTTPBasicAuth(obj.username, obj.password),
+        )
+    except Exception as e:
+        print(e)
+        print("Could not reach Sandbox at " + url)
+        exit(1)
+
+    check_response_status(resp)
+
 @sandbox_demobank.command("info", help="Return basic information of a bank 
account")
 @click.option(
     "--bank-account",
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
index 2bce4079..10d4b042 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
@@ -226,7 +226,7 @@ fun wireTransfer(
     return wireTransfer(
         debitAccount = args.first,
         creditAccount = args.second,
-        Demobank = args.third,
+        demobank = args.third,
         subject = subject,
         amount = amountObj.amount.toPlainString()
     )
@@ -244,7 +244,7 @@ fun wireTransfer(
 fun wireTransfer(
     debitAccount: BankAccountEntity,
     creditAccount: BankAccountEntity,
-    Demobank: DemobankConfigEntity,
+    demobank: DemobankConfigEntity,
     subject: String,
     amount: String,
 ): String {
@@ -262,12 +262,12 @@ fun wireTransfer(
             debtorName = getPersonNameFromCustomer(debitAccount.owner)
             this.subject = subject
             this.amount = amount
-            this.currency = Demobank.currency
+            this.currency = demobank.currency
             date = timeStamp
             accountServicerReference = transactionRef
             account = creditAccount
             direction = "CRDT"
-            this.demobank = Demobank
+            this.demobank = demobank
         }
         BankAccountTransactionEntity.new {
             creditorIban = creditAccount.iban
@@ -278,12 +278,12 @@ fun wireTransfer(
             debtorName = getPersonNameFromCustomer(debitAccount.owner)
             this.subject = subject
             this.amount = amount
-            this.currency = Demobank.currency
+            this.currency = demobank.currency
             date = timeStamp
             accountServicerReference = transactionRef
             account = debitAccount
             direction = "DBIT"
-            demobank = Demobank
+            this.demobank = demobank
         }
     }
     return transactionRef
@@ -306,10 +306,10 @@ fun getBankAccountFromPayto(paytoUri: String): 
BankAccountEntity {
 
 fun getBankAccountFromIban(iban: String): BankAccountEntity {
     return transaction {
-        BankAccountEntity.find(BankAccountsTable.iban eq iban)
-    }.firstOrNull() ?: throw SandboxError(
+        BankAccountEntity.find(BankAccountsTable.iban eq iban).firstOrNull()
+    } ?: throw SandboxError(
         HttpStatusCode.NotFound,
-        "Did not find a bank account for ${iban}"
+        "Did not find a bank account for $iban"
     )
 }
 
@@ -385,4 +385,32 @@ fun getEbicsSubscriberFromDetails(userID: String, 
partnerID: String, hostID: Str
             "Ebics subscriber not found"
         )
     }
+}
+
+/**
+ * This helper tries to:
+ * 1.  Authenticate the client.
+ * 2.  Extract the bank account's label from the request's path
+ * 3.  Return the bank account DB object if the client has access to it.
+ */
+fun getBankAccountWithAuth(call: ApplicationCall): BankAccountEntity {
+    val username = call.request.basicAuth()
+    val accountAccessed = call.getUriComponent("account_name")
+    val demobank = ensureDemobank(call)
+    val bankAccount = transaction {
+        val res = BankAccountEntity.find {
+            (BankAccountsTable.label eq accountAccessed).and(
+                BankAccountsTable.demoBank eq demobank.id
+            )
+        }.firstOrNull()
+        res
+    } ?: throw notFound("Account '$accountAccessed' not found")
+    // Check rights.
+    if (
+        WITH_AUTH
+        && (bankAccount.owner != username && username != "admin")
+    ) throw forbidden(
+        "Customer '$username' cannot access bank account '$accountAccessed'"
+    )
+    return bankAccount
 }
\ No newline at end of file
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
index a25503b8..7f19d2e3 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/JSON.kt
@@ -122,3 +122,13 @@ data class TalerWithdrawalSelection(
     val reserve_pub: String,
     val selected_exchange: String?
 )
+
+data class NewTransactionReq(
+    /**
+     * This Payto address must contain the wire transfer
+     * subject among its query parameters -- 'message' parameter.
+     */
+    val paytoUri: String,
+    // $currency:X.Y format
+    val amount: String
+)
\ No newline at end of file
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 5cdd8cd5..08945b33 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -84,7 +84,7 @@ val logger: Logger = 
LoggerFactory.getLogger("tech.libeufin.sandbox")
 private val currencyEnv: String? = System.getenv("LIBEUFIN_SANDBOX_CURRENCY")
 const val SANDBOX_DB_ENV_VAR_NAME = "LIBEUFIN_SANDBOX_DB_CONNECTION"
 private val adminPassword: String? = 
System.getenv("LIBEUFIN_SANDBOX_ADMIN_PASSWORD")
-private var WITH_AUTH = true
+var WITH_AUTH = true // Needed by helpers too, hence not making it private.
 
 data class SandboxError(
     val statusCode: HttpStatusCode,
@@ -1070,6 +1070,33 @@ val sandboxApp: Application.() -> Unit = {
             }
             // Talk to Web UI.
             route("/access-api") {
+                post("/accounts/{account_name}/transactions") {
+                    val bankAccount = getBankAccountWithAuth(call)
+                    val req = call.receive<NewTransactionReq>()
+                    val payto = parsePayto(req.paytoUri)
+                    val amount = parseAmount(req.amount)
+                    /**
+                     * Need a transaction block only to let the
+                     * 'demoBank' field of 'bankAccount' accessed.
+                     *
+                     * This could be fixed by making 'getBankAccountWithAuth()'
+                     * return a pair, consisting of the bank account and the 
demobank
+                     * hosting it.
+                     */
+                    transaction {
+                        wireTransfer(
+                            debitAccount = bankAccount,
+                            creditAccount = getBankAccountFromIban(payto.iban),
+                            demobank = bankAccount.demoBank,
+                            subject = payto.message ?: throw badRequest(
+                                "'message' query parameter missing in Payto 
address"
+                            ),
+                            amount = amount.amount.toPlainString()
+                        )
+                    }
+                    call.respond(object {})
+                    return@post
+                }
                 // Information about one withdrawal.
                 get("/accounts/{account_name}/withdrawals/{withdrawal_id}") {
                     val op = 
getWithdrawalOperation(call.getUriComponent("withdrawal_id"))
@@ -1178,7 +1205,7 @@ val sandboxApp: Application.() -> Unit = {
                                     "Cannot transfer funds without reserve 
public key."
                                 ),
                                 // provide the currency.
-                                Demobank = ensureDemobank(call)
+                                demobank = ensureDemobank(call)
                             )
                             wo.confirmationDone = true
                         }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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